Merge branch 'cross-chain-swap' of github.com:certusone/wormhole-nativeswap-example into cross-chain-swap

This commit is contained in:
Drew Sterioti 2022-01-23 21:35:04 +00:00
commit 6e3e5758b8
9 changed files with 794 additions and 81 deletions

View File

@ -1 +1,3 @@
.env
build/
node_modules/

447
react/package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "Cross Chain Swap",
"name": "NativeSwap",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "Cross Chain Swap",
"name": "NativeSwap",
"version": "0.1.0",
"dependencies": {
"@certusone/wormhole-sdk": "^0.1.6",
@ -33,6 +33,7 @@
},
"devDependencies": {
"@craco/craco": "^6.3.0",
"gh-pages": "^3.2.3",
"wasm-loader": "^1.3.0"
}
},
@ -9578,6 +9579,12 @@
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"node_modules/email-addresses": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
"integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
"dev": true
},
"node_modules/emittery": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
@ -11351,6 +11358,32 @@
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"node_modules/filename-reserved-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
"integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/filenamify": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
"integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
"dev": true,
"dependencies": {
"filename-reserved-regex": "^2.0.0",
"strip-outer": "^1.0.1",
"trim-repeated": "^1.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -12014,6 +12047,188 @@
"node": ">=0.10.0"
}
},
"node_modules/gh-pages": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz",
"integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==",
"dev": true,
"dependencies": {
"async": "^2.6.1",
"commander": "^2.18.0",
"email-addresses": "^3.0.1",
"filenamify": "^4.3.0",
"find-cache-dir": "^3.3.1",
"fs-extra": "^8.1.0",
"globby": "^6.1.0"
},
"bin": {
"gh-pages": "bin/gh-pages.js",
"gh-pages-clean": "bin/gh-pages-clean.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/gh-pages/node_modules/array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
"dev": true,
"dependencies": {
"array-uniq": "^1.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gh-pages/node_modules/find-cache-dir": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
"integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
"dev": true,
"dependencies": {
"commondir": "^1.0.1",
"make-dir": "^3.0.2",
"pkg-dir": "^4.1.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
}
},
"node_modules/gh-pages/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/gh-pages/node_modules/globby": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true,
"dependencies": {
"array-union": "^1.0.1",
"glob": "^7.0.3",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gh-pages/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/gh-pages/node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dev": true,
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/gh-pages/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/gh-pages/node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/gh-pages/node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/gh-pages/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"
}
},
"node_modules/gh-pages/node_modules/pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gh-pages/node_modules/pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"dependencies": {
"find-up": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/gh-pages/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@ -22340,6 +22555,27 @@
"node": ">=0.10.0"
}
},
"node_modules/strip-outer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
"dev": true,
"dependencies": {
"escape-string-regexp": "^1.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-outer/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/style-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
@ -23258,6 +23494,27 @@
"node": ">=8"
}
},
"node_modules/trim-repeated": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
"dev": true,
"dependencies": {
"escape-string-regexp": "^1.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/trim-repeated/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/true-case-path": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz",
@ -33059,6 +33316,12 @@
}
}
},
"email-addresses": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
"integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
"dev": true
},
"emittery": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
@ -34411,6 +34674,23 @@
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"filename-reserved-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
"integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
"dev": true
},
"filenamify": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
"integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
"dev": true,
"requires": {
"filename-reserved-regex": "^2.0.0",
"strip-outer": "^1.0.1",
"trim-repeated": "^1.0.0"
}
},
"filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@ -34943,6 +35223,135 @@
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
},
"gh-pages": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz",
"integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==",
"dev": true,
"requires": {
"async": "^2.6.1",
"commander": "^2.18.0",
"email-addresses": "^3.0.1",
"filenamify": "^4.3.0",
"find-cache-dir": "^3.3.1",
"fs-extra": "^8.1.0",
"globby": "^6.1.0"
},
"dependencies": {
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
"dev": true,
"requires": {
"array-uniq": "^1.0.1"
}
},
"find-cache-dir": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
"integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^3.0.2",
"pkg-dir": "^4.1.0"
}
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"globby": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
"dev": true,
"requires": {
"array-union": "^1.0.1",
"glob": "^7.0.3",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dev": true,
"requires": {
"semver": "^6.0.0"
}
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"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
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"dev": true,
"requires": {
"find-up": "^4.0.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@ -43080,6 +43489,23 @@
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"peer": true
},
"strip-outer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.2"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}
}
},
"style-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
@ -43777,6 +44203,23 @@
"punycode": "^2.1.1"
}
},
"trim-repeated": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.2"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}
}
},
"true-case-path": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz",

View File

@ -1,5 +1,6 @@
{
"name": "Cross Chain Swap",
"homepage": "https://certusone.github.io/wormhole-nativeswap-example",
"name": "NativeSwap",
"version": "0.1.0",
"private": true,
"dependencies": {
@ -30,7 +31,9 @@
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
},
"eslintConfig": {
"extends": [
@ -52,6 +55,7 @@
},
"devDependencies": {
"@craco/craco": "^6.3.0",
"gh-pages": "^3.2.3",
"wasm-loader": "^1.3.0"
}
}

View File

@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Cross Chain Swap</title>
<title>NativeSwap</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -0,0 +1,11 @@
import "../css/CircleLoader.css";
export default function CircleLoader() {
return (
<div id={"loaderContainer"}>
<div id={"circle"}>
<div id={"inner"}></div>
</div>
</div>
);
}

View File

@ -0,0 +1,89 @@
import { ChainId, CHAIN_ID_POLYGON, isEVMChain } from "@certusone/wormhole-sdk";
import { LinearProgress, makeStyles, Typography } from "@material-ui/core";
import { useEffect, useState } from "react";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2),
textAlign: "center",
},
message: {
marginTop: theme.spacing(1),
},
}));
export default function TransactionProgress({
chainId,
txBlockNumber,
step,
}: {
chainId: ChainId;
txBlockNumber: number | undefined;
step: number;
}) {
const classes = useStyles();
const { provider } = useEthereumProvider();
const [currentBlock, setCurrentBlock] = useState(0);
useEffect(() => {
if (step !== 1 || !txBlockNumber) return;
if (isEVMChain(chainId) && provider) {
let cancelled = false;
(async () => {
while (!cancelled) {
await new Promise((resolve) => setTimeout(resolve, 500));
try {
const newBlock = await provider.getBlockNumber();
if (!cancelled) {
setCurrentBlock(newBlock);
}
} catch (e) {
console.error(e);
}
}
})();
return () => {
cancelled = true;
};
}
}, [step, chainId, provider, txBlockNumber]);
const blockDiff =
txBlockNumber !== undefined && txBlockNumber && currentBlock
? currentBlock - txBlockNumber
: 0;
const expectedBlocks = 15;
let value;
let valueBuffer;
let message;
switch (step) {
case 1:
value = (blockDiff / expectedBlocks) * 50;
valueBuffer = 50;
message = `Waiting for ${blockDiff} / ${expectedBlocks} confirmations on ${
chainId === CHAIN_ID_POLYGON ? "Polygon" : "Ethereum"
}...`;
break;
case 2:
value = 50;
valueBuffer = 100;
message = "Waiting for relayer to complete swap...";
break;
case 3:
value = 100;
valueBuffer = 100;
message = "";
break;
}
return (
<div className={classes.root}>
<LinearProgress
variant="buffer"
value={value}
valueBuffer={valueBuffer}
/>
<Typography variant="body2" className={classes.message}>
{message}
</Typography>
</div>
);
}

View File

@ -0,0 +1,90 @@
:root {
--basis: linear-gradient(
160deg,
rgba(69, 74, 117, 0.473) 0%,
rgba(98, 104, 143, 0.445) 100%
),
linear-gradient(
45deg,
rgba(153, 69, 255, 0.411) 0%,
rgba(0, 209, 139, 0.404) 100%
);
/* --gradient1: rgb(26, 212, 150); */
/* --gradient2: rgb(176, 139, 221); */
--gradient1: rgb(117, 228, 187);
--gradient2: rgb(193, 164, 230);
}
#loaderContainer {
display: flex;
width: max-content;
height: max-content;
justify-content: center;
align-items: center;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes switch {
0% {
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 200px;
height: 200px;
box-shadow: 0 -130px 0 -75px var(--gradient1);
}
25% {
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 200px;
height: 200px;
box-shadow: 0 -130px 0 -75px var(--gradient1);
}
50% {
top: calc(100% - 55px);
width: 50px;
height: 50px;
box-shadow: 0 -130px 0 75px var(--gradient1);
transform: translateX(-50%) translateY(0);
}
75% {
top: calc(100% - 55px);
width: 50px;
height: 50px;
box-shadow: 0 -130px 0 75px var(--gradient1);
transform: translateX(-50%) translateY(0);
}
100% {
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 200px;
height: 200px;
box-shadow: 0 -130px 0 -75px var(--gradient1);
}
}
#circle {
width: 325px;
height: 325px;
display: block;
background: var(--basis);
border-radius: 500%;
position: relative;
animation: rotation 2s linear infinite;
}
#inner {
width: 200px;
height: 200px;
background: var(--gradient2);
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
border-radius: 100%;
box-shadow: 0 -130px 0 -75px #222;
animation: switch 8s ease-in-out infinite;
}

View File

@ -17,7 +17,6 @@ export default async function getIsTransferCompletedEvmWithRetry(
provider,
signedVAA
);
console.log("getIsTransferCompletedEth", result);
} catch (e) {
console.error(e);
}

View File

@ -1,4 +1,5 @@
import {
Collapse,
Container,
Link,
makeStyles,
@ -33,6 +34,9 @@ import { Alert } from "@material-ui/lab";
import parseError from "../utils/parseError";
import Settings from "../components/Settings";
import getIsTransferCompletedEvmWithRetry from "../utils/getIsTransferCompletedWithRetry";
import CircleLoader from "../components/CircleLoader";
import { ArrowForward, CheckCircleOutlineRounded } from "@material-ui/icons";
import SwapProgress from "../components/SwapProgress";
const useStyles = makeStyles((theme) => ({
bg: {
@ -115,6 +119,16 @@ const useStyles = makeStyles((theme) => ({
margin: "1rem",
display: "inline-block",
},
loaderHolder: {
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
},
successIcon: {
color: COLORS.green,
fontSize: "200px",
},
}));
const switchProviderNetwork = async (
@ -136,10 +150,11 @@ const switchProviderNetwork = async (
export default function Home() {
const classes = useStyles();
const [sourceTokenInfo, setSourceTokenInfo] = useState(WMATIC_TOKEN_INFO);
const [targetTokenInfo, setTargetTokenInfo] = useState(WETH_TOKEN_INFO);
const [sourceTokenInfo, setSourceTokenInfo] = useState(MATIC_TOKEN_INFO);
const [targetTokenInfo, setTargetTokenInfo] = useState(ETH_TOKEN_INFO);
const [amountIn, setAmountIn] = useState("");
const [amountOut, setAmountOut] = useState("0.0");
const [amountInUST, setAmountInUST] = useState("");
const [amountOut, setAmountOut] = useState("");
const [deadline, setDeadline] = useState("30");
const [slippage, setSlippage] = useState("1");
const [executor, setExecutor] = useState<UniswapToUniswapExecutor | null>(
@ -150,18 +165,25 @@ export default function Home() {
const [hasQuote, setHasQuote] = useState(false);
const { provider, signer } = useEthereumProvider();
const { enqueueSnackbar } = useSnackbar();
const [isFirstSwapComplete, setIsFirstSwapComplete] = useState(false);
const [isSecondSwapComplete, setIsSecondSwapComplete] = useState(false);
const [sourceTxBlockNumber, setSourceTxBlockNumber] = useState<
number | undefined
>(undefined);
const [hasSignedVAA, setHasSignedVAA] = useState(false);
const [relayerTimeoutString, setRelayerTimeoutString] = useState("");
const computeQuote = useCallback(() => {
(async () => {
setHasQuote(false);
setIsComputingQuote(true);
setAmountOut("");
try {
if (
parseFloat(amountIn) > 0 &&
!isNaN(parseFloat(deadline)) &&
!isNaN(parseFloat(slippage))
) {
setAmountOut("0.0");
const executor = new UniswapToUniswapExecutor();
await executor.initialize(
sourceTokenInfo.address,
@ -184,9 +206,12 @@ export default function Home() {
executor.tokens.dstOut.formatAmount(quote.dst.minAmountOut)
).toFixed(8)
);
setAmountInUST(
parseFloat(
executor.tokens.dstIn.formatAmount(quote.dst.amountIn)
).toFixed(2)
);
setHasQuote(true);
} else {
setAmountOut("0.0");
}
} catch (e) {
console.error(e);
@ -246,13 +271,28 @@ export default function Home() {
setTargetTokenInfo(ETH_TOKEN_INFO);
}
setAmountIn("");
setAmountOut("0.0");
setAmountOut("");
}, []);
const reset = useCallback(() => {
setIsSwapping(false);
setHasQuote(false);
setIsFirstSwapComplete(false);
setIsSecondSwapComplete(false);
setAmountIn("");
setAmountOut("");
setSourceTxBlockNumber(undefined);
setRelayerTimeoutString("");
}, []);
const handleSwapClick = useCallback(async () => {
if (provider && signer && executor) {
try {
setIsSwapping(true);
setIsFirstSwapComplete(false);
setHasSignedVAA(false);
setIsSecondSwapComplete(false);
setRelayerTimeoutString("");
await switchProviderNetwork(provider, sourceTokenInfo.chainId);
const sourceReceipt = await executor.approveAndSwap(signer);
@ -260,24 +300,17 @@ export default function Home() {
"firstSwapTransactionHash:",
sourceReceipt.transactionHash
);
setIsFirstSwapComplete(true);
setSourceTxBlockNumber(sourceReceipt.blockNumber);
// Wait for the guardian network to reach consensus and emit the signedVAA
enqueueSnackbar(null, {
content: <Alert severity="info">Fetching VAA</Alert>,
});
const { vaaBytes } = await getSignedVAAWithRetry(
WORMHOLE_RPC_HOSTS,
executor.srcExecutionParams.wormhole.chainId,
executor.vaaSearchParams.emitterAddress,
executor.vaaSearchParams.sequence
);
enqueueSnackbar(null, {
content: (
<Alert severity="info">
Fetched the Signed VAA, waiting for relayer to redeem it
</Alert>
),
});
setHasSignedVAA(true);
// Check if the signedVAA has redeemed by the relayer
const isCompleted = await getIsTransferCompletedEvmWithRetry(
executor.dstExecutionParams.wormhole.tokenBridgeAddress,
@ -287,30 +320,26 @@ export default function Home() {
3000,
40
);
if (isCompleted) {
enqueueSnackbar(null, {
content: <Alert severity="success">Swap completed</Alert>,
});
} else {
if (!isCompleted) {
// If the relayer hasn't redeemed the signedVAA, then manually redeem it ourselves
setRelayerTimeoutString(
"Timed out waiting for relayer to complete swap. You'll need to complete it yourself."
);
await switchProviderNetwork(provider, targetTokenInfo.chainId);
const targetReceipt = await executor.fetchVaaAndSwap(signer);
enqueueSnackbar(null, {
content: <Alert severity="success">Swap completed</Alert>,
});
console.info(
"secondSwapTransactionHash:",
targetReceipt.transactionHash
);
}
setIsSecondSwapComplete(true);
} catch (e: any) {
reset();
console.error(e);
enqueueSnackbar(null, {
content: <Alert severity="error">{parseError(e)}</Alert>,
});
}
setIsSwapping(false);
setAmountIn("");
}
}, [
provider,
@ -319,6 +348,7 @@ export default function Home() {
enqueueSnackbar,
sourceTokenInfo,
targetTokenInfo,
reset,
]);
const readyToSwap = provider && signer && hasQuote;
@ -328,58 +358,103 @@ export default function Home() {
<Container className={classes.centeredContainer} maxWidth="sm">
<div className={classes.titleBar}></div>
<Typography variant="h4" color="textSecondary">
Cross Chain Swap Demo
Wormhole NativeSwap Demo
</Typography>
<div className={classes.spacer} />
<Paper className={classes.mainPaper}>
<Settings
disabled={isSwapping || isComputingQuote}
slippage={slippage}
deadline={deadline}
onSlippageChange={handleSlippageChange}
onDeadlineChange={handleDeadlineChange}
/>
<TokenSelect
tokens={TOKEN_INFOS}
value={sourceTokenInfo.name}
onChange={handleSourceChange}
disabled={isSwapping || isComputingQuote}
></TokenSelect>
<Typography variant="subtitle1">Send</Typography>
<TextField
type="number"
value={amountIn}
disabled={isSwapping || isComputingQuote}
InputProps={{ disableUnderline: true }}
className={classes.numberField}
onChange={handleAmountChange}
placeholder="0.0"
></TextField>
<Collapse in={!isFirstSwapComplete}>
<Settings
disabled={isSwapping || isComputingQuote}
slippage={slippage}
deadline={deadline}
onSlippageChange={handleSlippageChange}
onDeadlineChange={handleDeadlineChange}
/>
<TokenSelect
tokens={TOKEN_INFOS}
value={sourceTokenInfo.name}
onChange={handleSourceChange}
disabled={isSwapping || isComputingQuote}
></TokenSelect>
<Typography variant="subtitle1">Send</Typography>
<TextField
type="number"
value={amountIn}
disabled={isSwapping || isComputingQuote}
InputProps={{ disableUnderline: true }}
className={classes.numberField}
onChange={handleAmountChange}
placeholder="0.0"
></TextField>
<div className={classes.spacer} />
<TokenSelect
tokens={TOKEN_INFOS}
value={targetTokenInfo.name}
onChange={() => {}}
disabled={true}
></TokenSelect>
<Typography variant="subtitle1">Receive (estimated)</Typography>
<TextField
type="number"
value={amountOut}
autoFocus={true}
InputProps={{ disableUnderline: true }}
className={classes.numberField}
inputProps={{ readOnly: true }}
placeholder="0.0"
></TextField>
<Typography variant="subtitle2">{`Slippage tolerance: ${slippage}%`}</Typography>
{!isSwapping && <EthereumSignerKey />}
<ButtonWithLoader
disabled={!readyToSwap || isSwapping}
showLoader={isSwapping}
onClick={handleSwapClick}
>
Swap
</ButtonWithLoader>
</Collapse>
<Collapse in={isFirstSwapComplete && !isSecondSwapComplete}>
<div className={classes.loaderHolder}>
<CircleLoader />
<div className={classes.spacer} />
<Typography variant="h5">
{`Your ${sourceTokenInfo.name} is being swapped to ${targetTokenInfo.name}`}
</Typography>
</div>
</Collapse>
<Collapse in={isSecondSwapComplete}>
<div className={classes.loaderHolder}>
<CheckCircleOutlineRounded
className={classes.successIcon}
fontSize={"inherit"}
/>
<Typography>Swap completed!</Typography>
<ButtonWithLoader onClick={() => reset()}>
Swap more tokens!
</ButtonWithLoader>
</div>
</Collapse>
<div className={classes.spacer} />
<TokenSelect
tokens={TOKEN_INFOS}
value={targetTokenInfo.name}
onChange={() => {}}
disabled={true}
></TokenSelect>
<Typography variant="subtitle1">Receive (estimated)</Typography>
<TextField
type="number"
value={amountOut}
autoFocus={true}
InputProps={{ disableUnderline: true }}
className={classes.numberField}
inputProps={{ readOnly: true }}
></TextField>
<Typography variant="subtitle2">{`Slippage tolerance: ${slippage}%`}</Typography>
{!isSwapping && <EthereumSignerKey />}
<ButtonWithLoader
disabled={!readyToSwap || isSwapping}
showLoader={isSwapping}
onClick={handleSwapClick}
>
Swap
</ButtonWithLoader>
{hasQuote && (
<Typography variant="subtitle1">
{`${amountIn} ${sourceTokenInfo.name} `}
<ArrowForward fontSize="inherit" />
{` ${amountInUST} UST `} <ArrowForward fontSize="inherit" />
{` ${amountOut} ${targetTokenInfo.name}`}
</Typography>
)}
{isFirstSwapComplete &&
!isSecondSwapComplete &&
!relayerTimeoutString && (
<SwapProgress
chainId={sourceTokenInfo.chainId}
txBlockNumber={sourceTxBlockNumber}
step={!hasSignedVAA ? 1 : !isSecondSwapComplete ? 2 : 3}
/>
)}
{relayerTimeoutString && (
<Typography variant="subtitle1">{relayerTimeoutString}</Typography>
)}
<div className={classes.spacer} />
<Typography variant="subtitle2" color="error">
WARNING: this is a Testnet release only