Merge branch 'main' of github.com:abacus-network/abacus-monorepo into trevor/multisig-validator-manager

pull/334/head
Trevor Porter 3 years ago
commit 3673557082
  1. 4
      .github/workflows/node.yml
  2. 612
      package-lock.json
  3. 12
      typescript/infra/src/core/deploy.ts
  4. 3
      typescript/sdk/.mocharc.json
  5. 5
      typescript/sdk/package.json
  6. 10
      typescript/sdk/src/core/contracts.ts
  7. 138
      typescript/sdk/src/core/environments/test.ts
  8. 8
      typescript/sdk/src/core/index.ts
  9. 24
      typescript/sdk/src/core/message.ts
  10. 264
      typescript/sdk/src/gas/calculator.ts
  11. 2
      typescript/sdk/src/gas/index.ts
  12. 13
      typescript/sdk/src/gas/token-prices.ts
  13. 64
      typescript/sdk/src/gas/utils.ts
  14. 7
      typescript/sdk/src/index.ts
  15. 1
      typescript/sdk/src/types.ts
  16. 148
      typescript/sdk/test/gas/calculator.test.ts
  17. 49
      typescript/sdk/test/utils.test.ts
  18. 103
      typescript/sdk/test/utils.ts
  19. 2
      typescript/sdk/tsconfig.json
  20. 4
      typescript/utils/src/utils.ts

@ -83,7 +83,9 @@ jobs:
path: ./*
key: ${{ github.sha }}
- name: test
- name: sdk
run: npm --prefix ./typescript/sdk run test
- name: infra
run: npm --prefix ./typescript/infra run test
test-sol:

612
package-lock.json generated

@ -3386,6 +3386,12 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@ungap/promise-all-settled": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
"dev": true
},
"node_modules/@yarnpkg/lockfile": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
@ -17199,6 +17205,18 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
@ -18628,6 +18646,18 @@
"integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=",
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
"dev": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/native-promise-only": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz",
@ -20677,6 +20707,15 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/serve-static": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
@ -24351,6 +24390,12 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"node_modules/workerpool": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
"integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
"dev": true
},
"node_modules/world-calendars": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.3.tgz",
@ -24787,6 +24832,18 @@
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"solidity/abacus-core": {
"name": "@abacus-network/core",
"version": "0.0.1",
@ -25112,10 +25169,12 @@
"@types/node": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"chai": "^4.3.6",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"fs": "0.0.1-security",
"mocha": "^9.2.2",
"prettier": "^2.4.1",
"typescript": "^4.4.3"
}
@ -25126,6 +25185,308 @@
"integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==",
"dev": true
},
"typescript/sdk/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"typescript/sdk/node_modules/camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/decamelize": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"typescript/sdk/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"typescript/sdk/node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true,
"bin": {
"flat": "cli.js"
}
},
"typescript/sdk/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"typescript/sdk/node_modules/is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"typescript/sdk/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"typescript/sdk/node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"dependencies": {
"p-locate": "^5.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
"integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": ">=10"
}
},
"typescript/sdk/node_modules/mocha": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
"integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
"dev": true,
"dependencies": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
"chokidar": "3.5.3",
"debug": "4.3.3",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
"glob": "7.2.0",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "4.2.1",
"ms": "2.1.3",
"nanoid": "3.3.1",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"which": "2.0.2",
"workerpool": "6.2.0",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
},
"bin": {
"_mocha": "bin/_mocha",
"mocha": "bin/mocha"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mochajs"
}
},
"typescript/sdk/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"typescript/sdk/node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"dependencies": {
"p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"typescript/sdk/node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"typescript/sdk/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"typescript/sdk/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"typescript/sdk/node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=10"
}
},
"typescript/sdk/node_modules/yargs-parser": {
"version": "20.2.4",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"typescript/sdk/node_modules/yargs-unparser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dev": true,
"dependencies": {
"camelcase": "^6.0.0",
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"typescript/utils": {
"name": "@abacus-network/utils",
"version": "0.0.7",
@ -25278,11 +25639,13 @@
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"celo-ethers-provider": "0.0.0",
"chai": "^4.3.6",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"ethers": "^5.4.7",
"fs": "0.0.1-security",
"mocha": "^9.2.2",
"prettier": "^2.4.1",
"typescript": "^4.4.3"
},
@ -25292,6 +25655,216 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.26.tgz",
"integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==",
"dev": true
},
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"camelcase": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true
},
"decamelize": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"dev": true
},
"diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"requires": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
}
},
"flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"is-plain-obj": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
"dev": true
},
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
"argparse": "^2.0.1"
}
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"requires": {
"p-locate": "^5.0.0"
}
},
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
"integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
"dev": true,
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
}
},
"minimatch": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
"integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mocha": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
"integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
"dev": true,
"requires": {
"@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
"chokidar": "3.5.3",
"debug": "4.3.3",
"diff": "5.0.0",
"escape-string-regexp": "4.0.0",
"find-up": "5.0.0",
"glob": "7.2.0",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "4.1.0",
"log-symbols": "4.1.0",
"minimatch": "4.2.1",
"ms": "2.1.3",
"nanoid": "3.3.1",
"serialize-javascript": "6.0.0",
"strip-json-comments": "3.1.1",
"supports-color": "8.1.1",
"which": "2.0.2",
"workerpool": "6.2.0",
"yargs": "16.2.0",
"yargs-parser": "20.2.4",
"yargs-unparser": "2.0.0"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"requires": {
"yocto-queue": "^0.1.0"
}
},
"p-locate": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
"requires": {
"p-limit": "^3.0.2"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {
"version": "20.2.4",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
"dev": true
},
"yargs-unparser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
"dev": true,
"requires": {
"camelcase": "^6.0.0",
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
}
}
}
},
@ -27958,6 +28531,12 @@
"eslint-visitor-keys": "^2.0.0"
}
},
"@ungap/promise-all-settled": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
"dev": true
},
"@yarnpkg/lockfile": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
@ -38654,6 +39233,12 @@
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true
},
"is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
@ -39831,6 +40416,12 @@
"integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=",
"dev": true
},
"nanoid": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
"dev": true
},
"native-promise-only": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz",
@ -41430,6 +42021,15 @@
}
}
},
"serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
"integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"serve-static": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
@ -44489,6 +45089,12 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"workerpool": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
"integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
"dev": true
},
"world-calendars": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/world-calendars/-/world-calendars-1.0.3.tgz",
@ -44837,6 +45443,12 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true
}
}
}

@ -21,6 +21,7 @@ import {
XAppConnectionManager__factory,
Outbox__factory,
Inbox__factory,
InterchainGasPaymaster__factory,
} from '@abacus-network/core';
import { DeployEnvironment, RustConfig } from '../config';
import { CoreConfig, MultisigValidatorManagerConfig } from './types';
@ -85,6 +86,12 @@ export class AbacusCoreDeployer extends AbacusAppDeployer<
[outboxMultisigValidatorManager.address],
);
const interchainGasPaymaster = await this.deployContract(
domain,
'InterchainGasPaymaster',
new InterchainGasPaymaster__factory(signer),
);
const xAppConnectionManager: XAppConnectionManager =
await this.deployContract(
domain,
@ -92,6 +99,10 @@ export class AbacusCoreDeployer extends AbacusAppDeployer<
new XAppConnectionManager__factory(signer),
);
await xAppConnectionManager.setOutbox(outbox.address, overrides);
await xAppConnectionManager.setInterchainGasPaymaster(
interchainGasPaymaster.address,
overrides,
);
const inboxMultisigValidatorManagers: Record<
types.Domain,
@ -159,6 +170,7 @@ export class AbacusCoreDeployer extends AbacusAppDeployer<
const addresses = {
upgradeBeaconController: upgradeBeaconController.address,
xAppConnectionManager: xAppConnectionManager.address,
interchainGasPaymaster: interchainGasPaymaster.address,
outboxMultisigValidatorManager: outboxMultisigValidatorManager.address,
inboxMultisigValidatorManagers: inboxMultisigValidatorManagerAddresses,
outbox: outbox.addresses,

@ -0,0 +1,3 @@
{
"require": ["ts-node/register"]
}

@ -8,18 +8,21 @@
"build": "tsc",
"check": "tsc --noEmit",
"prettier": "prettier --write ./src",
"prepublishOnly": "npm run build"
"prepublishOnly": "npm run build",
"test": "mocha --config .mocharc.json './test/**/*.test.ts'"
},
"license": "MIT OR Apache-2.0",
"devDependencies": {
"@types/node": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"chai": "^4.3.6",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"fs": "0.0.1-security",
"prettier": "^2.4.1",
"mocha": "^9.2.2",
"typescript": "^4.4.3"
},
"dependencies": {

@ -11,6 +11,8 @@ import {
Outbox__factory,
Inbox,
Inbox__factory,
InterchainGasPaymaster,
InterchainGasPaymaster__factory,
} from '@abacus-network/core';
import { types } from '@abacus-network/utils';
@ -20,6 +22,7 @@ import { ChainName, ProxiedAddress } from '../types';
export type CoreContractAddresses = {
upgradeBeaconController: types.Address;
xAppConnectionManager: types.Address;
interchainGasPaymaster: types.Address;
outbox: ProxiedAddress;
inboxes: Partial<Record<ChainName, ProxiedAddress>>;
outboxMultisigValidatorManager: types.Address;
@ -73,4 +76,11 @@ export class CoreContracts extends AbacusAppContracts<CoreContractAddresses> {
this.connection,
);
}
get interchainGasPaymaster(): InterchainGasPaymaster {
return InterchainGasPaymaster__factory.connect(
this.addresses.interchainGasPaymaster,
this.connection,
);
}
}

@ -1,13 +1,14 @@
export const addresses = {
alfajores: {
upgradeBeaconController: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
xAppConnectionManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707',
xAppConnectionManager: '0x0165878A594ca255338adfa4d48449f69242Eb8F',
interchainGasPaymaster: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707',
outboxMultisigValidatorManager:
'0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512',
inboxMultisigValidatorManagers: {
kovan: '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853',
mumbai: '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0',
fuji: '0x0B306BF915C4d645ff596e518fAf3F9669b97016',
kovan: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318',
mumbai: '0x9A676e781A523b5d0C0e43731313A708CB607508',
fuji: '0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE',
},
outbox: {
proxy: '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9',
@ -16,118 +17,121 @@ export const addresses = {
},
inboxes: {
kovan: {
proxy: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788',
implementation: '0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6',
beacon: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318',
proxy: '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0',
implementation: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788',
beacon: '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e',
},
mumbai: {
proxy: '0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82',
implementation: '0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6',
beacon: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318',
proxy: '0x0B306BF915C4d645ff596e518fAf3F9669b97016',
implementation: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788',
beacon: '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e',
},
fuji: {
proxy: '0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1',
implementation: '0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6',
beacon: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318',
proxy: '0x68B1D87F95878fE05B998F19b66F4baba5De1aed',
implementation: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788',
beacon: '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e',
},
},
},
kovan: {
upgradeBeaconController: '0x68B1D87F95878fE05B998F19b66F4baba5De1aed',
xAppConnectionManager: '0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44',
upgradeBeaconController: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d',
xAppConnectionManager: '0x7a2088a1bFc9d81c55368AE168C2C02570cB814F',
interchainGasPaymaster: '0x4A679253410272dd5232B3Ff7cF5dbB88f295319',
outboxMultisigValidatorManager:
'0x3Aa5ebB10DC797CAC828524e59A333d0A371443c',
'0x59b670e9fA9D0A427751Af201D676719a970857b',
inboxMultisigValidatorManagers: {
alfajores: '0x4A679253410272dd5232B3Ff7cF5dbB88f295319',
mumbai: '0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E',
fuji: '0x9E545E3C0baAB3E08CdfD552C960A1050f373042',
alfajores: '0x67d269191c92Caf3cD7723F116c85e6E9bf55933',
mumbai: '0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9',
fuji: '0xf5059a5D33d5853360D16C683c16e67980206f36',
},
outbox: {
proxy: '0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1',
implementation: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d',
beacon: '0x59b670e9fA9D0A427751Af201D676719a970857b',
proxy: '0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f',
implementation: '0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1',
beacon: '0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44',
},
inboxes: {
alfajores: {
proxy: '0xc5a5C42992dECbae36851359345FE25997F5C42d',
implementation: '0x7a2088a1bFc9d81c55368AE168C2C02570cB814F',
beacon: '0x09635F643e140090A9A8Dcd712eD6285858ceBef',
proxy: '0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB',
implementation: '0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E',
beacon: '0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690',
},
mumbai: {
proxy: '0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690',
implementation: '0x7a2088a1bFc9d81c55368AE168C2C02570cB814F',
beacon: '0x09635F643e140090A9A8Dcd712eD6285858ceBef',
proxy: '0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8',
implementation: '0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E',
beacon: '0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690',
},
fuji: {
proxy: '0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9',
implementation: '0x7a2088a1bFc9d81c55368AE168C2C02570cB814F',
beacon: '0x09635F643e140090A9A8Dcd712eD6285858ceBef',
proxy: '0x95401dc811bb5740090279Ba06cfA8fcF6113778',
implementation: '0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E',
beacon: '0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690',
},
},
},
mumbai: {
upgradeBeaconController: '0x851356ae760d987E095750cCeb3bC6014560891C',
xAppConnectionManager: '0x4826533B4897376654Bb4d4AD88B7faFD0C98528',
upgradeBeaconController: '0x70e0bA845a1A0F2DA3359C97E0285013525FFC49',
xAppConnectionManager: '0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00',
interchainGasPaymaster: '0x9d4454B023096f34B160D6B654540c56A1F81688',
outboxMultisigValidatorManager:
'0xf5059a5D33d5853360D16C683c16e67980206f36',
'0x4826533B4897376654Bb4d4AD88B7faFD0C98528',
inboxMultisigValidatorManagers: {
alfajores: '0x0E801D84Fa97b50751Dbf25036d067dCf18858bF',
kovan: '0x809d550fca64d94Bd9F66E60752A544199cfAC3D',
fuji: '0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154',
alfajores: '0x4c5859f0F772848b2D91F1D83E2Fe57935348029',
kovan: '0x82e01223d51Eb87e16A03E24687EDF0F294da6f1',
fuji: '0x7bc06c482DEAd17c0e297aFbC32f6e63d3846650',
},
outbox: {
proxy: '0x70e0bA845a1A0F2DA3359C97E0285013525FFC49',
implementation: '0x95401dc811bb5740090279Ba06cfA8fcF6113778',
beacon: '0x998abeb3E57409262aE5b751f60747921B33613E',
proxy: '0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf',
implementation: '0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf',
beacon: '0x0E801D84Fa97b50751Dbf25036d067dCf18858bF',
},
inboxes: {
alfajores: {
proxy: '0x5eb3Bc0a489C5A8288765d2336659EbCA68FCd00',
implementation: '0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf',
beacon: '0x9d4454B023096f34B160D6B654540c56A1F81688',
proxy: '0xb7278A61aa25c888815aFC32Ad3cC52fF24fE575',
implementation: '0x1291Be112d480055DaFd8a610b7d1e203891C274',
beacon: '0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154',
},
kovan: {
proxy: '0x4c5859f0F772848b2D91F1D83E2Fe57935348029',
implementation: '0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf',
beacon: '0x9d4454B023096f34B160D6B654540c56A1F81688',
proxy: '0x2bdCC0de6bE1f7D2ee689a0342D76F52E8EFABa3',
implementation: '0x1291Be112d480055DaFd8a610b7d1e203891C274',
beacon: '0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154',
},
fuji: {
proxy: '0xb7278A61aa25c888815aFC32Ad3cC52fF24fE575',
implementation: '0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf',
beacon: '0x9d4454B023096f34B160D6B654540c56A1F81688',
proxy: '0xc351628EB244ec633d5f21fBD6621e1a683B1181',
implementation: '0x1291Be112d480055DaFd8a610b7d1e203891C274',
beacon: '0x5f3f1dBD7B74C6B46e8c44f98792A1dAf8d69154',
},
},
},
fuji: {
upgradeBeaconController: '0x82e01223d51Eb87e16A03E24687EDF0F294da6f1',
xAppConnectionManager: '0xFD471836031dc5108809D173A067e8486B9047A3',
upgradeBeaconController: '0xcbEAF3BDe82155F56486Fb5a1072cb8baAf547cc',
xAppConnectionManager: '0x1fA02b2d6A771842690194Cf62D91bdd92BfE28d',
interchainGasPaymaster: '0x5081a39b8A5f0E35a8D959395a630b68B74Dd30f',
outboxMultisigValidatorManager:
'0x2bdCC0de6bE1f7D2ee689a0342D76F52E8EFABa3',
'0x1429859428C0aBc9C2C47C8Ee9FBaf82cFA0F20f',
inboxMultisigValidatorManagers: {
alfajores: '0x1429859428C0aBc9C2C47C8Ee9FBaf82cFA0F20f',
kovan: '0x1fA02b2d6A771842690194Cf62D91bdd92BfE28d',
mumbai: '0x4C4a2f8c81640e47606d3fd77B353E87Ba015584',
alfajores: '0x4C4a2f8c81640e47606d3fd77B353E87Ba015584',
kovan: '0x51A1ceB83B83F1985a81C295d1fF28Afef186E02',
mumbai: '0x0355B7B8cb128fA5692729Ab3AAa199C1753f726',
},
outbox: {
proxy: '0xc351628EB244ec633d5f21fBD6621e1a683B1181',
implementation: '0x7969c5eD335650692Bc04293B07F5BF2e7A673C0',
beacon: '0x7bc06c482DEAd17c0e297aFbC32f6e63d3846650',
},
inboxes: {
alfajores: {
proxy: '0x922D6956C99E12DFeB3224DEA977D0939758A1Fe',
implementation: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07',
beacon: '0x162A433068F51e18b7d13932F27e66a3f99E6890',
},
inboxes: {
alfajores: {
proxy: '0xD8a5a9b31c3C0232E196d518E89Fd8bF83AcAd43',
implementation: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823',
beacon: '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2',
},
kovan: {
proxy: '0xdbC43Ba45381e02825b14322cDdd15eC4B3164E6',
implementation: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07',
beacon: '0x162A433068F51e18b7d13932F27e66a3f99E6890',
proxy: '0x36b58F5C1969B7b6591D752ea6F5486D069010AB',
implementation: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823',
beacon: '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2',
},
mumbai: {
proxy: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823',
implementation: '0xB0D4afd8879eD9F52b28595d31B441D079B2Ca07',
beacon: '0x162A433068F51e18b7d13932F27e66a3f99E6890',
proxy: '0x202CCe504e04bEd6fC0521238dDf04Bc9E8E15aB',
implementation: '0x21dF544947ba3E8b3c32561399E88B52Dc8b2823',
beacon: '0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2',
},
},
},

@ -6,4 +6,10 @@ export {
AnnotatedDispatch,
AnnotatedLifecycleEvent,
} from './events';
export { AbacusMessage, AbacusStatus, MessageStatus } from './message';
export {
AbacusMessage,
AbacusStatus,
MessageStatus,
ParsedMessage,
parseMessage,
} from './message';

@ -24,7 +24,7 @@ import {
} from './events';
export type ParsedMessage = {
from: number;
origin: number;
sender: string;
nonce: number;
destination: number;
@ -64,13 +64,13 @@ export type EventCache = {
*/
export function parseMessage(message: string): ParsedMessage {
const buf = Buffer.from(arrayify(message));
const from = buf.readUInt32BE(0);
const origin = buf.readUInt32BE(0);
const sender = hexlify(buf.slice(4, 36));
const nonce = buf.readUInt32BE(36);
const destination = buf.readUInt32BE(40);
const recipient = hexlify(buf.slice(44, 76));
const body = hexlify(buf.slice(76));
return { from, sender, nonce, destination, recipient, body };
return { origin, sender, nonce, destination, recipient, body };
}
/**
@ -89,8 +89,11 @@ export class AbacusMessage {
this.core = core;
this.message = parseMessage(dispatch.event.args.message);
this.dispatch = dispatch;
this.outbox = core.mustGetContracts(this.message.from).outbox;
this.inbox = core.mustGetInbox(this.message.from, this.message.destination);
this.outbox = core.mustGetContracts(this.message.origin).outbox;
this.inbox = core.mustGetInbox(
this.message.origin,
this.message.destination,
);
this.cache = {};
}
@ -421,17 +424,10 @@ export class AbacusMessage {
}
/**
* The domain from which the message was sent
*/
get from(): number {
return this.message.from;
}
/**
* The domain from which the message was sent. Alias for `from`
* The domain from which the message was sent.
*/
get origin(): number {
return this.from;
return this.message.origin;
}
/**

@ -0,0 +1,264 @@
import { BigNumber, ethers, FixedNumber } from 'ethers';
import { utils } from '@abacus-network/utils';
import { AbacusCore, ParsedMessage } from '..';
import { convertDecimalValue, mulBigAndFixed } from './utils';
import { DefaultTokenPriceGetter, TokenPriceGetter } from './token-prices';
/**
* A note on arithmetic:
* The ethers.BigNumber implementation behaves very similar to Solidity's
* number handling by not supporting decimals. To avoid adding another big
* number implementation as a dependency, we use ethers.FixedNumber, a
* fixed point implementation intended to model how Solidity's half-supported
* fixed point numbers work, see https://docs.soliditylang.org/en/v0.8.13/types.html#fixed-point-numbers).
*
* Generally, ceiling is used rather than floor here to err on the side of over-
* estimating amounts.
*/
// If a domain doesn't specify how many decimals their native token has, 18 is used.
const DEFAULT_TOKEN_DECIMALS = 18;
export interface InterchainGasCalculatorConfig {
/**
* A multiplier applied to the estimated origin token payment amount.
* This should be high enough to account for movements in token exchange
* rates and gas prices.
* @defaultValue 1.25
*/
paymentEstimateMultiplier?: string;
/**
* An amount of additional gas to add to the estimated gas of processing a message.
* Only used when estimating a payment from a message.
* @defaultValue 50,000
*/
messageGasEstimateBuffer?: string;
/**
* Used to get the native token prices of the origin and destination chains.
* @defaultValue An instance of DefaultTokenPriceGetter.
*/
tokenPriceGetter?: TokenPriceGetter;
}
/**
* Calculates interchain gas payments.
*/
export class InterchainGasCalculator {
core: AbacusCore;
tokenPriceGetter: TokenPriceGetter;
paymentEstimateMultiplier: ethers.FixedNumber;
messageGasEstimateBuffer: ethers.BigNumber;
constructor(core: AbacusCore, config?: InterchainGasCalculatorConfig) {
this.core = core;
this.tokenPriceGetter =
config?.tokenPriceGetter ?? new DefaultTokenPriceGetter();
this.paymentEstimateMultiplier = FixedNumber.from(
config?.paymentEstimateMultiplier ?? '1.25',
);
this.messageGasEstimateBuffer = BigNumber.from(
config?.messageGasEstimateBuffer ?? 50_000,
);
}
/**
* Calculates the estimated payment for an amount of gas on the destination chain,
* denominated in the native token of the origin chain. Considers the exchange
* rate between the native tokens of the origin and destination chains, and the
* suggested gas price on the destination chain. Applies the multiplier
* `paymentEstimateMultiplier`.
* @param originDomain The domain of the origin chain.
* @param destinationDomain The domain of the destination chain.
* @param destinationGas The amount of gas to pay for on the destination chain.
* @returns An estimated amount of origin chain tokens to cover gas costs of the
* message on the destination chain.
*/
async estimatePaymentForGasAmount(
originDomain: number,
destinationDomain: number,
destinationGas: BigNumber,
): Promise<BigNumber> {
const destinationGasPrice = await this.suggestedGasPrice(destinationDomain);
const destinationCostWei = destinationGas.mul(destinationGasPrice);
// Convert from destination domain native tokens to origin domain native tokens.
const originCostWei = await this.convertBetweenNativeTokens(
destinationDomain,
originDomain,
destinationCostWei,
);
// Applies a multiplier
return mulBigAndFixed(
originCostWei,
this.paymentEstimateMultiplier,
true, // ceil
);
}
/**
* Calculates the estimated payment to process the message on its destination chain,
* denominated in the native token of the origin chain. The destination gas is
* determined by estimating the gas to process the provided message, which is then used
* to calculate the payment using {@link estimatePaymentForGasAmount}.
* @param message The parsed message to estimate payment for.
* @returns An estimated amount of origin chain tokens to cover gas costs of the
* message on the destination chain.
*/
async estimatePaymentForMessage(message: ParsedMessage) {
const destinationGas = await this.estimateGasForMessage(message);
return this.estimatePaymentForGasAmount(
message.origin,
message.destination,
destinationGas,
);
}
/**
* Using the exchange rates provided by tokenPriceGetter, returns the amount of
* `toDomain` native tokens equivalent in value to the provided `fromAmount` of
* `fromDomain` native tokens. Accounts for differences in the decimals of the tokens.
* @param fromDomain The domain whose native token is being converted from.
* @param toDomain The domain whose native token is being converted into.
* @param fromAmount The amount of `fromDomain` native tokens to convert from.
* @returns The amount of `toDomain` native tokens whose value is equivalent to
* `fromAmount` of `fromDomain` native tokens.
*/
async convertBetweenNativeTokens(
fromDomain: number,
toDomain: number,
fromAmount: BigNumber,
): Promise<BigNumber> {
// A FixedNumber that doesn't care what the decimals of the from/to
// tokens are -- it is just the amount of whole from tokens that a single
// whole to token is equivalent in value to.
const exchangeRate = await this.getExchangeRate(toDomain, fromDomain);
// Apply the exchange rate to the amount. This does not yet account for differences in
// decimals between the two tokens.
const exchangeRateProduct = mulBigAndFixed(
fromAmount,
exchangeRate,
true, // ceil
);
// Converts exchangeRateProduct to having the correct number of decimals.
return convertDecimalValue(
exchangeRateProduct,
this.nativeTokenDecimals(fromDomain),
this.nativeTokenDecimals(toDomain),
);
}
/**
* @param baseDomain The domain whose native token is the base asset.
* @param quoteDomain The domain whose native token is the quote asset.
* @returns The exchange rate of the native tokens of the baseDomain and the quoteDomain.
* I.e. the number of whole quote tokens a single whole base token is equivalent
* in value to.
*/
async getExchangeRate(
baseDomain: number,
quoteDomain: number,
): Promise<FixedNumber> {
const baseUsd = await this.tokenPriceGetter.getNativeTokenUsdPrice(
baseDomain,
);
const quoteUsd = await this.tokenPriceGetter.getNativeTokenUsdPrice(
quoteDomain,
);
// This operation is called "unsafe" because of the unintuitive rounding that
// can occur due to fixed point arithmetic. We're not overly concerned about perfect
// precision because we're operating with fixed128x18, which has 18 decimals of
// precision, and gas payments are regardless expected to have a generous buffer to account
// for movements in native token prices or gas prices.
// For more details on FixedPoint arithmetic being "unsafe", see
// https://github.com/ethers-io/ethers.js/issues/1322#issuecomment-787430115.
return quoteUsd.divUnsafe(baseUsd);
}
/**
* Gets a suggested gas price for a domain.
* @param domain The domain of the chain to estimate gas prices for.
* @returns The suggested gas price in wei on the destination chain.
*/
async suggestedGasPrice(domain: number): Promise<BigNumber> {
const provider = this.core.mustGetProvider(domain);
return provider.getGasPrice();
}
/**
* Gets the number of decimals of the provided domain's native token.
* @param domain The domain.
* @returns The number of decimals of `domain`'s native token.
*/
nativeTokenDecimals(domain: number) {
return (
this.core.mustGetDomain(domain).nativeTokenDecimals ??
DEFAULT_TOKEN_DECIMALS
);
}
/**
* Estimates the amount of gas required to process a message on its destination chain.
* This does not assume the Inbox of the destination domain has a checkpoint that
* the message is included in. Therefore, we estimate the gas by summing:
* 1. The intrinsic gas cost of a transaction on the destination chain.
* 2. Any gas costs imposed by operations in the Inbox, including proving
* the message and logic surrounding the processing of a message.
* 3. The estimated gas consumption of a direct call to the `handle`
* function of the recipient address using the correct parameters and
* setting the `from` address of the transaction to the address of the inbox.
* 4. A buffer to account for inaccuracies in the above estimations.
* @returns The estimated gas required to process the message on the destination chain.
*/
async estimateGasForMessage(message: ParsedMessage): Promise<BigNumber> {
const provider = this.core.mustGetProvider(message.destination);
const inbox = this.core.mustGetInbox(message.origin, message.destination);
const handlerInterface = new ethers.utils.Interface([
'function handle(uint32,bytes32,bytes)',
]);
// Estimates a direct call to the `handle` function of the recipient
// with the `from` address set to the inbox.
// This includes intrinsic gas, so no need to add it
const directHandleCallGas = await provider.estimateGas({
to: utils.bytes32ToAddress(message.recipient),
from: inbox.address,
data: handlerInterface.encodeFunctionData('handle', [
message.origin,
message.sender,
message.body,
]),
});
// directHandleCallGas includes the intrinsic gas
return directHandleCallGas
.add(this.inboxProvingAndProcessingGas)
.add(this.messageGasEstimateBuffer);
}
/**
* @returns A generous estimation of the gas consumption of all prove and process
* operations in Inbox.sol, excluding:
* 1. Intrinsic gas.
* 2. Any gas consumed within a `handle` function when processing a message once called.
*/
get inboxProvingAndProcessingGas() {
// This does not consider that different domains can possibly have different gas costs.
// Consider this being configurable for each domain, or investigate ways to estimate
// this over RPC.
//
// This number was arrived at by estimating the proving and processing of a message
// whose recipient contract included only an empty fallback function. The estimated
// gas cost was ~100,000 which includes the intrinsic cost, but 150,000 is chosen as
// a generous buffer.
return 150_000;
}
}

@ -0,0 +1,2 @@
export { InterchainGasCalculator } from './calculator';
export { DefaultTokenPriceGetter, TokenPriceGetter } from './token-prices';

@ -0,0 +1,13 @@
import { FixedNumber } from 'ethers';
import { NameOrDomain } from '../types';
export interface TokenPriceGetter {
getNativeTokenUsdPrice(domain: NameOrDomain): Promise<FixedNumber>;
}
// TODO implement in following PR
export class DefaultTokenPriceGetter implements TokenPriceGetter {
getNativeTokenUsdPrice(_domain: NameOrDomain): Promise<FixedNumber> {
return Promise.resolve(FixedNumber.from('12.34'));
}
}

@ -0,0 +1,64 @@
import { BigNumber, FixedNumber } from 'ethers';
/**
* Converts a BigNumber to a FixedNumber of the format fixed128x18.
* @param big The BigNumber to convert.
* @returns A FixedNumber representation of a BigNumber.
*/
export function bigToFixed(big: BigNumber): FixedNumber {
return FixedNumber.from(big.toString());
}
/**
* Converts a FixedNumber (of any format) to a BigNumber.
* @param fixed The FixedNumber to convert.
* @param ceil If true, the ceiling of fixed is used. Otherwise, the floor is used.
* @returns A BigNumber representation of a FixedNumber.
*/
export function fixedToBig(
fixed: FixedNumber,
ceil: boolean = false,
): BigNumber {
const fixedAsInteger = ceil ? fixed.ceiling() : fixed.floor();
return BigNumber.from(fixedAsInteger.toFormat('fixed256x0').toString());
}
/**
* Multiplies a BigNumber by a FixedNumber, returning the BigNumber product.
* @param big The BigNumber to multiply.
* @param fixed The FixedNumber to multiply.
* @param ceil If true, the ceiling of the product is used. Otherwise, the floor is used.
* @returns The BigNumber product.
*/
export function mulBigAndFixed(
big: BigNumber,
fixed: FixedNumber,
ceil: boolean = false,
): BigNumber {
// Converts big to a FixedNumber, multiplies it by fixed, and converts the product back
// to a BigNumber.
return fixedToBig(fixed.mulUnsafe(bigToFixed(big)), ceil);
}
/**
* Converts a value with `fromDecimals` decimals to a value with `toDecimals` decimals.
* Incurs a loss of precision when `fromDecimals` > `toDecimals`.
* @param value The value to convert.
* @param fromDecimals The number of decimals `value` has.
* @param toDecimals The number of decimals to convert `value` to.
* @returns `value` represented with `toDecimals` decimals.
*/
export function convertDecimalValue(
value: BigNumber,
fromDecimals: number,
toDecimals: number,
): BigNumber {
if (fromDecimals === toDecimals) {
return value;
} else if (fromDecimals > toDecimals) {
return value.div(10 ** (fromDecimals - toDecimals));
} else {
// if (fromDecimals < toDecimals)
return value.mul(10 ** (toDecimals - fromDecimals));
}
}

@ -9,6 +9,8 @@ export {
CoreContracts,
CoreContractAddresses,
MessageStatus,
ParsedMessage,
parseMessage,
} from './core';
export {
Annotated,
@ -33,4 +35,9 @@ export {
export { AbacusAppContracts } from './contracts';
export { AbacusApp } from './app';
export { domains } from './domains';
export {
DefaultTokenPriceGetter,
InterchainGasCalculator,
TokenPriceGetter,
} from './gas';
export { utils } from './utils';

@ -46,6 +46,7 @@ export type ChainName = MainnetChainNames | TestnetChainNames | TestChainNames;
export interface Domain {
id: number;
name: ChainName;
nativeTokenDecimals?: number;
paginate?: Pagination;
}

@ -0,0 +1,148 @@
import { expect } from 'chai';
import { BigNumber, ethers, FixedNumber } from 'ethers';
import { utils } from '@abacus-network/utils';
import { AbacusCore, InterchainGasCalculator, ParsedMessage } from '../..';
import { MockProvider, MockTokenPriceGetter, testAddresses } from '../utils';
describe('InterchainGasCalculator', () => {
const originDomain = 1;
const destinationDomain = 2;
let core: AbacusCore;
let provider: MockProvider;
let tokenPriceGetter: MockTokenPriceGetter;
let calculator: InterchainGasCalculator;
before(() => {
core = new AbacusCore(testAddresses);
provider = new MockProvider();
core.registerProvider('test1', provider);
core.registerProvider('test2', provider);
tokenPriceGetter = new MockTokenPriceGetter();
// Origin domain token
tokenPriceGetter.setTokenPrice(originDomain, 10);
// Destination domain token
tokenPriceGetter.setTokenPrice(destinationDomain, 5);
});
beforeEach(() => {
calculator = new InterchainGasCalculator(core, {
tokenPriceGetter,
});
});
afterEach(() => {
provider.clearMethodResolveValues();
});
describe('estimatePaymentForGasAmount', () => {
it('estimates origin token payment from a specified destination gas amount', async () => {
const destinationGas = BigNumber.from(100_000);
// Set destination gas price to 10 wei
provider.setMethodResolveValue('getGasPrice', BigNumber.from(10));
// Set paymentEstimateMultiplier to 1 just to test easily
calculator.paymentEstimateMultiplier = FixedNumber.from(1);
const estimatedPayment = await calculator.estimatePaymentForGasAmount(
originDomain,
destinationDomain,
destinationGas,
);
// 100_000 dest gas * 10 gas price * ($5 per origin token / $10 per origin token)
expect(estimatedPayment.toNumber()).to.equal(500_000);
});
});
describe('estimatePaymentForMessage', () => {
it('estimates origin token payment from a specified message', async () => {
// Set the estimated destination gas
const estimatedDestinationGas = 100_000;
calculator.estimateGasForMessage = () => Promise.resolve(BigNumber.from(estimatedDestinationGas));
// Set destination gas price to 10 wei
calculator.suggestedGasPrice = (_) => Promise.resolve(BigNumber.from(10));
// Set paymentEstimateMultiplier to 1 just to test easily
calculator.paymentEstimateMultiplier = FixedNumber.from(1);
const zeroAddressBytes32 = utils.addressToBytes32(ethers.constants.AddressZero);
const message: ParsedMessage = {
origin: originDomain,
sender: zeroAddressBytes32,
nonce: 0,
destination: destinationDomain,
recipient: zeroAddressBytes32,
body: '0x12345678',
};
const estimatedPayment = await calculator.estimatePaymentForMessage(message);
// 100_000 dest gas * 10 gas price * ($5 per origin token / $10 per origin token)
expect(estimatedPayment.toNumber()).to.equal(500_000);
});
});
describe('convertBetweenNativeTokens', () => {
it('converts using the USD value of origin and destination native tokens', async () => {
const destinationWei = BigNumber.from('1000');
const originWei = await calculator.convertBetweenNativeTokens(
destinationDomain,
originDomain,
destinationWei,
);
expect(originWei.toNumber()).to.equal(500);
});
it('considers when the origin token decimals > the destination token decimals', async () => {
calculator.nativeTokenDecimals = (domain: number) => {
if (domain === originDomain) {
return 20;
}
return 18;
};
const destinationWei = BigNumber.from('1000');
const originWei = await calculator.convertBetweenNativeTokens(
destinationDomain,
originDomain,
destinationWei,
);
expect(originWei.toNumber()).to.equal(50000);
});
it('considers when the origin token decimals < the destination token decimals', async () => {
calculator.nativeTokenDecimals = (domain: number) => {
if (domain === originDomain) {
return 16;
}
return 18;
};
const destinationWei = BigNumber.from('1000');
const originWei = await calculator.convertBetweenNativeTokens(
destinationDomain,
originDomain,
destinationWei,
);
expect(originWei.toNumber()).to.equal(5);
})
});
describe('suggestedGasPrice', () => {
it('gets the gas price from the provider', async () => {
const gasPrice = 1000;
provider.setMethodResolveValue('getGasPrice', BigNumber.from(gasPrice));
expect(
(await calculator.suggestedGasPrice(destinationDomain)).toNumber()
).to.equal(gasPrice);
});
});
});

@ -0,0 +1,49 @@
import { expect } from 'chai';
import { BigNumber, FixedNumber } from 'ethers';
import { bigToFixed, fixedToBig, mulBigAndFixed } from '../src/gas/utils';
describe('utils', () => {
describe('bigToFixed', () => {
it('converts a BigNumber to a FixedNumber', () => {
const big = BigNumber.from('1234');
const fixed = bigToFixed(big);
expect(fixed.toUnsafeFloat()).to.equal(1234);
});
});
describe('fixedToBig', () => {
it('converts a FixedNumber to a floored BigNumber', () => {
const fixed = FixedNumber.from('12.34');
const big = fixedToBig(fixed);
expect(big.toNumber()).to.equal(12);
});
it('converts a FixedNumber to a ceilinged BigNumber', () => {
const fixed = FixedNumber.from('12.34');
const big = fixedToBig(fixed, true);
expect(big.toNumber()).to.equal(13);
});
});
describe('mulBigAndFixed', () => {
it('gets the floored product of a BigNumber and FixedNumber', () => {
const big = BigNumber.from('1000');
const fixed = FixedNumber.from('1.2345');
const product = mulBigAndFixed(big, fixed);
expect(product.toNumber()).to.equal(1234);
});
it('gets the ceilinged product of a BigNumber and FixedNumber', () => {
const big = BigNumber.from('1000');
const fixed = FixedNumber.from('1.2345');
const product = mulBigAndFixed(big, fixed, true);
expect(product.toNumber()).to.equal(1235);
});
});
});

@ -0,0 +1,103 @@
import { ethers, FixedNumber } from 'ethers';
import { NameOrDomain } from '../src';
const ZERO_ADDRESS = ethers.constants.AddressZero;
export const testAddresses = {
test1: {
upgradeBeaconController: ZERO_ADDRESS,
xAppConnectionManager: ZERO_ADDRESS,
validatorManager: ZERO_ADDRESS,
interchainGasPaymaster: ZERO_ADDRESS,
outbox: {
proxy: ZERO_ADDRESS,
implementation: ZERO_ADDRESS,
beacon: ZERO_ADDRESS,
},
inboxes: {
test2: {
proxy: ZERO_ADDRESS,
implementation: ZERO_ADDRESS,
beacon: ZERO_ADDRESS,
},
},
},
test2: {
upgradeBeaconController: ZERO_ADDRESS,
xAppConnectionManager: ZERO_ADDRESS,
validatorManager: ZERO_ADDRESS,
interchainGasPaymaster: ZERO_ADDRESS,
outbox: {
proxy: ZERO_ADDRESS,
implementation: ZERO_ADDRESS,
beacon: ZERO_ADDRESS,
},
inboxes: {
test1: {
proxy: ZERO_ADDRESS,
implementation: ZERO_ADDRESS,
beacon: ZERO_ADDRESS,
},
},
},
};
const MOCK_NETWORK = {
name: 'MockNetwork',
chainId: 1337,
};
// A mock ethers Provider used for testing with mocked provider functionality
export class MockProvider extends ethers.providers.BaseProvider {
private methodResolveValues: { [key: string]: any };
constructor() {
super(MOCK_NETWORK);
this.methodResolveValues = {};
}
// Required to be implemented or the BaseProvider throws
async detectNetwork() {
return Promise.resolve(MOCK_NETWORK);
}
perform(method: string, params: any): Promise<any> {
const value = this.methodResolveValues[method]
if (value) {
return Promise.resolve(value);
}
return super.perform(method, params);
}
setMethodResolveValue(method: string, value: any) {
this.methodResolveValues[method] = value;
}
clearMethodResolveValues() {
this.methodResolveValues = {};
}
}
// A mock TokenPriceGetter intended to be used by tests when mocking token prices
export class MockTokenPriceGetter {
private tokenPrices: { [domain: number]: FixedNumber }
constructor() {
this.tokenPrices = {};
}
getNativeTokenUsdPrice(domain: NameOrDomain): Promise<FixedNumber> {
const price = this.tokenPrices[domain as number];
if (price) {
return Promise.resolve(price);
}
throw Error(`No price for domain ${domain}`);
}
setTokenPrice(domain: number, price: string | number) {
this.tokenPrices[domain] = FixedNumber.from(price);
}
}

@ -4,7 +4,7 @@
"outDir": "./dist/",
"rootDir": "./src/"
},
"exclude": ["./node_modules/", "./dist/"],
"exclude": ["./node_modules/", "./dist/", "./test/"],
"include": [
"./src/*.ts",
"./src/**/*.ts"

@ -34,6 +34,10 @@ export function addressToBytes32(address: Address): string {
.toLowerCase();
}
export function bytes32ToAddress(bytes32: string): Address {
return ethers.utils.getAddress(bytes32.slice(-40));
}
export const formatMessage = (
localDomain: Domain,
senderAddr: Address,

Loading…
Cancel
Save