sdk for migration & progress on lp_ui
Change-Id: I4ac855f1795ecffe50c68c428e530b215ba4b8e9
This commit is contained in:
parent
5b51dffe6d
commit
8a90b50aeb
|
@ -0,0 +1,28 @@
|
|||
const { addBeforeLoader, loaderByName } = require("@craco/craco");
|
||||
|
||||
module.exports = {
|
||||
webpack: {
|
||||
configure: (webpackConfig) => {
|
||||
const wasmExtensionRegExp = /\.wasm$/;
|
||||
webpackConfig.resolve.extensions.push(".wasm");
|
||||
|
||||
webpackConfig.module.rules.forEach((rule) => {
|
||||
(rule.oneOf || []).forEach((oneOf) => {
|
||||
if (oneOf.loader && oneOf.loader.indexOf("file-loader") >= 0) {
|
||||
oneOf.exclude.push(wasmExtensionRegExp);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const wasmLoader = {
|
||||
test: /\.wasm$/,
|
||||
include: /node_modules\/(bridge|token-bridge)/,
|
||||
loaders: ["wasm-loader"],
|
||||
};
|
||||
|
||||
addBeforeLoader(webpackConfig, loaderByName("file-loader"), wasmLoader);
|
||||
|
||||
return webpackConfig;
|
||||
},
|
||||
},
|
||||
};
|
|
@ -32,6 +32,10 @@
|
|||
"react-scripts": "4.0.3",
|
||||
"typescript": "^4.4.2",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@craco/craco": "^6.3.0",
|
||||
"wasm-loader": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"../sdk/js": {
|
||||
|
@ -1289,6 +1293,42 @@
|
|||
"node": ">=0.1.95"
|
||||
}
|
||||
},
|
||||
"node_modules/@craco/craco": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@craco/craco/-/craco-6.3.0.tgz",
|
||||
"integrity": "sha512-SCnfEQxT/6NAbU/3sIWw7gQXtzjjiTp/EZFdJTd8inPURILIy0YajrC2p8qBG2KhFo5cwgOrEDyaGyAFvvuyuA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"lodash": "^4.17.15",
|
||||
"semver": "^7.3.2",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"bin": {
|
||||
"craco": "bin/craco.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-scripts": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@craco/craco/node_modules/semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/convert-colors": {
|
||||
"version": "1.4.0",
|
||||
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==",
|
||||
|
@ -11571,6 +11611,15 @@
|
|||
"url": "https://tidelift.com/funding/github/npm/loglevel"
|
||||
}
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
|
@ -17905,6 +17954,58 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-dce": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
||||
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.0.0-beta.39",
|
||||
"@babel/traverse": "^7.0.0-beta.39",
|
||||
"@babel/types": "^7.0.0-beta.39",
|
||||
"babylon": "^7.0.0-beta.39",
|
||||
"webassembly-interpreter": "0.0.30"
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-dce/node_modules/babylon": {
|
||||
"version": "7.0.0-beta.47",
|
||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
||||
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"babylon": "bin/babylon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-loader": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/wasm-loader/-/wasm-loader-1.3.0.tgz",
|
||||
"integrity": "sha512-R4s75XH+o8qM+WaRrAU9S2rbAMDzob18/S3V8R9ZoFpZkPWLAohWWlzWAp1ybeTkOuuku/X1zJtxiV0pBYxZww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loader-utils": "^1.1.0",
|
||||
"wasm-dce": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"wasm-dce": "1.x"
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-loader/node_modules/loader-utils": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
|
||||
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "1.7.5",
|
||||
"integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
|
||||
|
@ -18039,6 +18140,34 @@
|
|||
"version": "1.1.2",
|
||||
"integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig=="
|
||||
},
|
||||
"node_modules/webassembly-floating-point-hex-parser": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
||||
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/webassembly-interpreter": {
|
||||
"version": "0.0.30",
|
||||
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
||||
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.0.0-beta.36",
|
||||
"long": "^3.2.0",
|
||||
"webassembly-floating-point-hex-parser": "0.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"wasm": "lib/bin/repl.js",
|
||||
"wasm2wast": "lib/bin/wasm2wast.js",
|
||||
"wasmast": "lib/bin/wasmast.js",
|
||||
"wasmdump": "lib/bin/wasmdump.js",
|
||||
"wasmrun": "lib/bin/wasmrun.js",
|
||||
"wastast": "lib/bin/wastast.js"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "6.1.0",
|
||||
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
|
||||
|
@ -18420,6 +18549,15 @@
|
|||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-merge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
||||
"integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-sources": {
|
||||
"version": "1.4.3",
|
||||
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
|
||||
|
@ -19938,6 +20076,29 @@
|
|||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@craco/craco": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@craco/craco/-/craco-6.3.0.tgz",
|
||||
"integrity": "sha512-SCnfEQxT/6NAbU/3sIWw7gQXtzjjiTp/EZFdJTd8inPURILIy0YajrC2p8qBG2KhFo5cwgOrEDyaGyAFvvuyuA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"lodash": "^4.17.15",
|
||||
"semver": "^7.3.2",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@csstools/convert-colors": {
|
||||
"version": "1.4.0",
|
||||
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
|
||||
|
@ -27780,6 +27941,12 @@
|
|||
"version": "1.7.1",
|
||||
"integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw=="
|
||||
},
|
||||
"long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=",
|
||||
"dev": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
|
@ -32583,6 +32750,50 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"wasm-dce": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wasm-dce/-/wasm-dce-1.0.2.tgz",
|
||||
"integrity": "sha512-Fq1+nu43ybsjSnBquLrW/cULmKs61qbv9k8ep13QUe0nABBezMoNAA+j6QY66MW0/eoDVDp1rjXDqQ2VKyS/Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/core": "^7.0.0-beta.39",
|
||||
"@babel/traverse": "^7.0.0-beta.39",
|
||||
"@babel/types": "^7.0.0-beta.39",
|
||||
"babylon": "^7.0.0-beta.39",
|
||||
"webassembly-interpreter": "0.0.30"
|
||||
},
|
||||
"dependencies": {
|
||||
"babylon": {
|
||||
"version": "7.0.0-beta.47",
|
||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.47.tgz",
|
||||
"integrity": "sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"wasm-loader": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/wasm-loader/-/wasm-loader-1.3.0.tgz",
|
||||
"integrity": "sha512-R4s75XH+o8qM+WaRrAU9S2rbAMDzob18/S3V8R9ZoFpZkPWLAohWWlzWAp1ybeTkOuuku/X1zJtxiV0pBYxZww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^1.1.0",
|
||||
"wasm-dce": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"loader-utils": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
|
||||
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.7.5",
|
||||
"integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
|
||||
|
@ -32688,6 +32899,23 @@
|
|||
"version": "1.1.2",
|
||||
"integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig=="
|
||||
},
|
||||
"webassembly-floating-point-hex-parser": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/webassembly-floating-point-hex-parser/-/webassembly-floating-point-hex-parser-0.1.2.tgz",
|
||||
"integrity": "sha512-TUf1H++8U10+stJbFydnvrpG5Sznz5Rilez/oZlV5zI0C/e4cSxd8rALAJ8VpTvjVWxLmL3SVSJUK6Ap9AoiNg==",
|
||||
"dev": true
|
||||
},
|
||||
"webassembly-interpreter": {
|
||||
"version": "0.0.30",
|
||||
"resolved": "https://registry.npmjs.org/webassembly-interpreter/-/webassembly-interpreter-0.0.30.tgz",
|
||||
"integrity": "sha512-+Jdy2piEvz9T5j751mOE8+rBO12p+nNW6Fg4kJZ+zP1oUfsm+151sbAbM8AFxWTURmWCGP+r8Lxwfv3pzN1bCQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0-beta.36",
|
||||
"long": "^3.2.0",
|
||||
"webassembly-floating-point-hex-parser": "0.1.2"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "6.1.0",
|
||||
"integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
|
||||
|
@ -33093,6 +33321,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webpack-merge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
||||
"integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"webpack-sources": {
|
||||
"version": "1.4.3",
|
||||
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
|
||||
|
|
|
@ -29,9 +29,10 @@
|
|||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"preinstall": "npm ci --prefix ../sdk/js && npm run build --prefix ../sdk/js",
|
||||
"start": "craco start",
|
||||
"build": "craco build",
|
||||
"test": "craco test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -51,5 +52,9 @@
|
|||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@craco/craco": "^6.3.0",
|
||||
"wasm-loader": "^1.3.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
export const value = "";
|
||||
import { clusterApiUrl } from "@solana/web3.js";
|
||||
|
||||
export const MIGRATION_PROGRAM_ADDRESS =
|
||||
process.env.REACT_APP_CLUSTER === "testnet"
|
||||
? ""
|
||||
: "Ex9bCdVMSfx7EzB3pgSi2R4UHwJAXvTw18rBQm5YQ8gK";
|
||||
|
||||
export const SOLANA_URL =
|
||||
process.env.REACT_APP_CLUSTER === "testnet"
|
||||
? clusterApiUrl("testnet")
|
||||
: "http://localhost:8899";
|
||||
|
|
|
@ -0,0 +1,577 @@
|
|||
import { PublicKey, AccountInfo } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
import { deserializeUnchecked } from "borsh";
|
||||
import { BinaryReader, BinaryWriter } from "borsh";
|
||||
const base58: any = require("bs58");
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const METADATA_REPLACE = new RegExp("\u0000", "g");
|
||||
export const EDITION_MARKER_BIT_SIZE = 248;
|
||||
export const METADATA_PREFIX = "metadata";
|
||||
export const EDITION = "edition";
|
||||
|
||||
export class LazyAccountInfoProxy<T> {
|
||||
executable: boolean = false;
|
||||
owner: StringPublicKey = "";
|
||||
lamports: number = 0;
|
||||
|
||||
get data() {
|
||||
return undefined as unknown as T;
|
||||
}
|
||||
}
|
||||
|
||||
export interface LazyAccountInfo {
|
||||
executable: boolean;
|
||||
owner: StringPublicKey;
|
||||
lamports: number;
|
||||
data: [string, string];
|
||||
}
|
||||
|
||||
const PubKeysInternedMap = new Map<string, PublicKey>();
|
||||
|
||||
export const toPublicKey = (key: string | PublicKey) => {
|
||||
if (typeof key !== "string") {
|
||||
return key;
|
||||
}
|
||||
|
||||
let result = PubKeysInternedMap.get(key);
|
||||
if (!result) {
|
||||
result = new PublicKey(key);
|
||||
PubKeysInternedMap.set(key, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export interface PublicKeyStringAndAccount<T> {
|
||||
pubkey: string;
|
||||
account: AccountInfo<T>;
|
||||
}
|
||||
|
||||
export const WRAPPED_SOL_MINT = new PublicKey(
|
||||
"So11111111111111111111111111111111111111112"
|
||||
);
|
||||
|
||||
export const TOKEN_PROGRAM_ID = new PublicKey(
|
||||
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
|
||||
);
|
||||
|
||||
export const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey(
|
||||
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
|
||||
);
|
||||
|
||||
export const BPF_UPGRADE_LOADER_ID = new PublicKey(
|
||||
"BPFLoaderUpgradeab1e11111111111111111111111"
|
||||
);
|
||||
|
||||
export const MEMO_ID = new PublicKey(
|
||||
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
|
||||
);
|
||||
|
||||
export const METADATA_PROGRAM_ID =
|
||||
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" as StringPublicKey;
|
||||
|
||||
export const VAULT_ID =
|
||||
"vau1zxA2LbssAUEF7Gpw91zMM1LvXrvpzJtmZ58rPsn" as StringPublicKey;
|
||||
|
||||
export const AUCTION_ID =
|
||||
"auctxRXPeJoc4817jDhf4HbjnhEcr1cCXenosMhK5R8" as StringPublicKey;
|
||||
|
||||
export const METAPLEX_ID =
|
||||
"p1exdMJcjVao65QdewkaZRUnU6VPSXhus9n2GzWfh98" as StringPublicKey;
|
||||
|
||||
export const SYSTEM = new PublicKey("11111111111111111111111111111111");
|
||||
|
||||
export const getStoreID = async (storeOwnerAddress?: string) => {
|
||||
if (!storeOwnerAddress) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const programs = await findProgramAddress(
|
||||
[
|
||||
Buffer.from("metaplex"),
|
||||
toPublicKey(METAPLEX_ID).toBuffer(),
|
||||
toPublicKey(storeOwnerAddress).toBuffer(),
|
||||
],
|
||||
toPublicKey(METAPLEX_ID)
|
||||
);
|
||||
const storeAddress = programs[0];
|
||||
|
||||
return storeAddress;
|
||||
};
|
||||
|
||||
export const setProgramIds = async (store?: string) => {
|
||||
STORE = store ? toPublicKey(store) : undefined;
|
||||
};
|
||||
|
||||
let STORE: PublicKey | undefined;
|
||||
|
||||
export const programIds = () => {
|
||||
return {
|
||||
token: TOKEN_PROGRAM_ID,
|
||||
associatedToken: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
|
||||
bpf_upgrade_loader: BPF_UPGRADE_LOADER_ID,
|
||||
system: SYSTEM,
|
||||
metadata: METADATA_PROGRAM_ID,
|
||||
memo: MEMO_ID,
|
||||
vault: VAULT_ID,
|
||||
auction: AUCTION_ID,
|
||||
metaplex: METAPLEX_ID,
|
||||
store: STORE,
|
||||
};
|
||||
};
|
||||
|
||||
export const findProgramAddress = async (
|
||||
seeds: (Buffer | Uint8Array)[],
|
||||
programId: PublicKey
|
||||
) => {
|
||||
const key =
|
||||
"pda-" +
|
||||
seeds.reduce((agg, item) => agg + item.toString("hex"), "") +
|
||||
programId.toString();
|
||||
let cached = localStorage.getItem(key);
|
||||
if (cached) {
|
||||
const value = JSON.parse(cached);
|
||||
|
||||
return [value.key, parseInt(value.nonce)] as [string, number];
|
||||
}
|
||||
|
||||
const result = await PublicKey.findProgramAddress(seeds, programId);
|
||||
|
||||
try {
|
||||
localStorage.setItem(
|
||||
key,
|
||||
JSON.stringify({
|
||||
key: result[0].toBase58(),
|
||||
nonce: result[1],
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return [result[0].toBase58(), result[1]] as [string, number];
|
||||
};
|
||||
|
||||
export type StringPublicKey = string;
|
||||
|
||||
export enum MetadataKey {
|
||||
Uninitialized = 0,
|
||||
MetadataV1 = 4,
|
||||
EditionV1 = 1,
|
||||
MasterEditionV1 = 2,
|
||||
MasterEditionV2 = 6,
|
||||
EditionMarker = 7,
|
||||
}
|
||||
|
||||
export async function getEdition(
|
||||
tokenMint: StringPublicKey
|
||||
): Promise<StringPublicKey> {
|
||||
const PROGRAM_IDS = programIds();
|
||||
|
||||
return (
|
||||
await findProgramAddress(
|
||||
[
|
||||
Buffer.from(METADATA_PREFIX),
|
||||
toPublicKey(PROGRAM_IDS.metadata).toBuffer(),
|
||||
toPublicKey(tokenMint).toBuffer(),
|
||||
Buffer.from(EDITION),
|
||||
],
|
||||
toPublicKey(PROGRAM_IDS.metadata)
|
||||
)
|
||||
)[0];
|
||||
}
|
||||
|
||||
class CreateMetadataArgs {
|
||||
instruction: number = 0;
|
||||
data: Data;
|
||||
isMutable: boolean;
|
||||
|
||||
constructor(args: { data: Data; isMutable: boolean }) {
|
||||
this.data = args.data;
|
||||
this.isMutable = args.isMutable;
|
||||
}
|
||||
}
|
||||
class UpdateMetadataArgs {
|
||||
instruction: number = 1;
|
||||
data: Data | null;
|
||||
// Not used by this app, just required for instruction
|
||||
updateAuthority: StringPublicKey | null;
|
||||
primarySaleHappened: boolean | null;
|
||||
constructor(args: {
|
||||
data?: Data;
|
||||
updateAuthority?: string;
|
||||
primarySaleHappened: boolean | null;
|
||||
}) {
|
||||
this.data = args.data ? args.data : null;
|
||||
this.updateAuthority = args.updateAuthority ? args.updateAuthority : null;
|
||||
this.primarySaleHappened = args.primarySaleHappened;
|
||||
}
|
||||
}
|
||||
|
||||
export class Creator {
|
||||
address: StringPublicKey;
|
||||
verified: boolean;
|
||||
share: number;
|
||||
|
||||
constructor(args: {
|
||||
address: StringPublicKey;
|
||||
verified: boolean;
|
||||
share: number;
|
||||
}) {
|
||||
this.address = args.address;
|
||||
this.verified = args.verified;
|
||||
this.share = args.share;
|
||||
}
|
||||
}
|
||||
|
||||
export class Data {
|
||||
name: string;
|
||||
symbol: string;
|
||||
uri: string;
|
||||
sellerFeeBasisPoints: number;
|
||||
creators: Creator[] | null;
|
||||
constructor(args: {
|
||||
name: string;
|
||||
symbol: string;
|
||||
uri: string;
|
||||
sellerFeeBasisPoints: number;
|
||||
creators: Creator[] | null;
|
||||
}) {
|
||||
this.name = args.name;
|
||||
this.symbol = args.symbol;
|
||||
this.uri = args.uri;
|
||||
this.sellerFeeBasisPoints = args.sellerFeeBasisPoints;
|
||||
this.creators = args.creators;
|
||||
}
|
||||
}
|
||||
|
||||
export class Metadata {
|
||||
key: MetadataKey;
|
||||
updateAuthority: StringPublicKey;
|
||||
mint: StringPublicKey;
|
||||
data: Data;
|
||||
primarySaleHappened: boolean;
|
||||
isMutable: boolean;
|
||||
editionNonce: number | null;
|
||||
|
||||
// set lazy
|
||||
masterEdition?: StringPublicKey;
|
||||
edition?: StringPublicKey;
|
||||
|
||||
constructor(args: {
|
||||
updateAuthority: StringPublicKey;
|
||||
mint: StringPublicKey;
|
||||
data: Data;
|
||||
primarySaleHappened: boolean;
|
||||
isMutable: boolean;
|
||||
editionNonce: number | null;
|
||||
}) {
|
||||
this.key = MetadataKey.MetadataV1;
|
||||
this.updateAuthority = args.updateAuthority;
|
||||
this.mint = args.mint;
|
||||
this.data = args.data;
|
||||
this.primarySaleHappened = args.primarySaleHappened;
|
||||
this.isMutable = args.isMutable;
|
||||
this.editionNonce = args.editionNonce;
|
||||
}
|
||||
|
||||
public async init() {
|
||||
const edition = await getEdition(this.mint);
|
||||
this.edition = edition;
|
||||
this.masterEdition = edition;
|
||||
}
|
||||
}
|
||||
|
||||
export class Edition {
|
||||
key: MetadataKey;
|
||||
/// Points at MasterEdition struct
|
||||
parent: StringPublicKey;
|
||||
/// Starting at 0 for master record, this is incremented for each edition minted.
|
||||
edition: BN;
|
||||
|
||||
constructor(args: {
|
||||
key: MetadataKey;
|
||||
parent: StringPublicKey;
|
||||
edition: BN;
|
||||
}) {
|
||||
this.key = MetadataKey.EditionV1;
|
||||
this.parent = args.parent;
|
||||
this.edition = args.edition;
|
||||
}
|
||||
}
|
||||
|
||||
export class MasterEditionV1 {
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
/// Can be used to mint tokens that give one-time permission to mint a single limited edition.
|
||||
printingMint: StringPublicKey;
|
||||
/// If you don't know how many printing tokens you are going to need, but you do know
|
||||
/// you are going to need some amount in the future, you can use a token from this mint.
|
||||
/// Coming back to token metadata with one of these tokens allows you to mint (one time)
|
||||
/// any number of printing tokens you want. This is used for instance by Auction Manager
|
||||
/// with participation NFTs, where we dont know how many people will bid and need participation
|
||||
/// printing tokens to redeem, so we give it ONE of these tokens to use after the auction is over,
|
||||
/// because when the auction begins we just dont know how many printing tokens we will need,
|
||||
/// but at the end we will. At the end it then burns this token with token-metadata to
|
||||
/// get the printing tokens it needs to give to bidders. Each bidder then redeems a printing token
|
||||
/// to get their limited editions.
|
||||
oneTimePrintingAuthorizationMint: StringPublicKey;
|
||||
|
||||
constructor(args: {
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
printingMint: StringPublicKey;
|
||||
oneTimePrintingAuthorizationMint: StringPublicKey;
|
||||
}) {
|
||||
this.key = MetadataKey.MasterEditionV1;
|
||||
this.supply = args.supply;
|
||||
this.maxSupply = args.maxSupply;
|
||||
this.printingMint = args.printingMint;
|
||||
this.oneTimePrintingAuthorizationMint =
|
||||
args.oneTimePrintingAuthorizationMint;
|
||||
}
|
||||
}
|
||||
|
||||
export class MasterEditionV2 {
|
||||
key: MetadataKey;
|
||||
supply: BN;
|
||||
maxSupply?: BN;
|
||||
|
||||
constructor(args: { key: MetadataKey; supply: BN; maxSupply?: BN }) {
|
||||
this.key = MetadataKey.MasterEditionV2;
|
||||
this.supply = args.supply;
|
||||
this.maxSupply = args.maxSupply;
|
||||
}
|
||||
}
|
||||
|
||||
class CreateMasterEditionArgs {
|
||||
instruction: number = 10;
|
||||
maxSupply: BN | null;
|
||||
constructor(args: { maxSupply: BN | null }) {
|
||||
this.maxSupply = args.maxSupply;
|
||||
}
|
||||
}
|
||||
|
||||
class MintPrintingTokensArgs {
|
||||
instruction: number = 9;
|
||||
supply: BN;
|
||||
|
||||
constructor(args: { supply: BN }) {
|
||||
this.supply = args.supply;
|
||||
}
|
||||
}
|
||||
|
||||
export class EditionMarker {
|
||||
key: MetadataKey;
|
||||
ledger: number[];
|
||||
|
||||
constructor(args: { key: MetadataKey; ledger: number[] }) {
|
||||
this.key = MetadataKey.EditionMarker;
|
||||
this.ledger = args.ledger;
|
||||
}
|
||||
|
||||
editionTaken(edition: number) {
|
||||
const editionOffset = edition % EDITION_MARKER_BIT_SIZE;
|
||||
const indexOffset = Math.floor(editionOffset / 8);
|
||||
|
||||
if (indexOffset > 30) {
|
||||
throw Error("bad index for edition");
|
||||
}
|
||||
|
||||
const positionInBitsetFromRight = 7 - (editionOffset % 8);
|
||||
|
||||
const mask = Math.pow(2, positionInBitsetFromRight);
|
||||
|
||||
const appliedMask = this.ledger[indexOffset] & mask;
|
||||
|
||||
// eslint-disable-next-line
|
||||
return appliedMask != 0;
|
||||
}
|
||||
}
|
||||
|
||||
export const METADATA_SCHEMA = new Map<any, any>([
|
||||
[
|
||||
CreateMetadataArgs,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["instruction", "u8"],
|
||||
["data", Data],
|
||||
["isMutable", "u8"], // bool
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
UpdateMetadataArgs,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["instruction", "u8"],
|
||||
["data", { kind: "option", type: Data }],
|
||||
["updateAuthority", { kind: "option", type: "pubkeyAsString" }],
|
||||
["primarySaleHappened", { kind: "option", type: "u8" }],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
CreateMasterEditionArgs,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["instruction", "u8"],
|
||||
["maxSupply", { kind: "option", type: "u64" }],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
MintPrintingTokensArgs,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["instruction", "u8"],
|
||||
["supply", "u64"],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
MasterEditionV1,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["key", "u8"],
|
||||
["supply", "u64"],
|
||||
["maxSupply", { kind: "option", type: "u64" }],
|
||||
["printingMint", "pubkeyAsString"],
|
||||
["oneTimePrintingAuthorizationMint", "pubkeyAsString"],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
MasterEditionV2,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["key", "u8"],
|
||||
["supply", "u64"],
|
||||
["maxSupply", { kind: "option", type: "u64" }],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
Edition,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["key", "u8"],
|
||||
["parent", "pubkeyAsString"],
|
||||
["edition", "u64"],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
Data,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["name", "string"],
|
||||
["symbol", "string"],
|
||||
["uri", "string"],
|
||||
["sellerFeeBasisPoints", "u16"],
|
||||
["creators", { kind: "option", type: [Creator] }],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
Creator,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["address", "pubkeyAsString"],
|
||||
["verified", "u8"],
|
||||
["share", "u8"],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
Metadata,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["key", "u8"],
|
||||
["updateAuthority", "pubkeyAsString"],
|
||||
["mint", "pubkeyAsString"],
|
||||
["data", Data],
|
||||
["primarySaleHappened", "u8"], // bool
|
||||
["isMutable", "u8"], // bool
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
EditionMarker,
|
||||
{
|
||||
kind: "struct",
|
||||
fields: [
|
||||
["key", "u8"],
|
||||
["ledger", [31]],
|
||||
],
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
export const extendBorsh = () => {
|
||||
(BinaryReader.prototype as any).readPubkey = function () {
|
||||
const reader = this as unknown as BinaryReader;
|
||||
const array = reader.readFixedArray(32);
|
||||
return new PublicKey(array);
|
||||
};
|
||||
|
||||
(BinaryWriter.prototype as any).writePubkey = function (value: PublicKey) {
|
||||
const writer = this as unknown as BinaryWriter;
|
||||
writer.writeFixedArray(value.toBuffer());
|
||||
};
|
||||
|
||||
(BinaryReader.prototype as any).readPubkeyAsString = function () {
|
||||
const reader = this as unknown as BinaryReader;
|
||||
const array = reader.readFixedArray(32);
|
||||
return base58.encode(array) as StringPublicKey;
|
||||
};
|
||||
|
||||
(BinaryWriter.prototype as any).writePubkeyAsString = function (
|
||||
value: StringPublicKey
|
||||
) {
|
||||
const writer = this as unknown as BinaryWriter;
|
||||
writer.writeFixedArray(base58.decode(value));
|
||||
};
|
||||
};
|
||||
|
||||
extendBorsh();
|
||||
|
||||
export const decodeMetadata = (buffer: Buffer): Metadata => {
|
||||
const metadata = deserializeUnchecked(
|
||||
METADATA_SCHEMA,
|
||||
Metadata,
|
||||
buffer
|
||||
) as Metadata;
|
||||
metadata.data.name = metadata.data.name.replace(METADATA_REPLACE, "");
|
||||
metadata.data.uri = metadata.data.uri.replace(METADATA_REPLACE, "");
|
||||
metadata.data.symbol = metadata.data.symbol.replace(METADATA_REPLACE, "");
|
||||
return metadata;
|
||||
};
|
||||
|
||||
export const getMetadataAddress = async (
|
||||
mintKey: string
|
||||
): Promise<[PublicKey, number]> => {
|
||||
const seeds = [
|
||||
Buffer.from("metadata"),
|
||||
new PublicKey(METADATA_PROGRAM_ID).toBuffer(),
|
||||
new PublicKey(mintKey).toBuffer(),
|
||||
];
|
||||
return PublicKey.findProgramAddress(
|
||||
seeds,
|
||||
new PublicKey(METADATA_PROGRAM_ID)
|
||||
);
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
import { MintLayout } from "@solana/spl-token";
|
||||
import { WalletContextState } from "@solana/wallet-adapter-react";
|
||||
import {
|
||||
AccountInfo,
|
||||
Connection,
|
||||
PublicKey,
|
||||
Transaction,
|
||||
TransactionInstruction,
|
||||
} from "@solana/web3.js";
|
||||
|
||||
export async function sendSignAndConfirmInstruction(
|
||||
wallet: WalletContextState,
|
||||
connection: Connection,
|
||||
instruction: TransactionInstruction
|
||||
) {
|
||||
console.log("instruction being sent", instruction);
|
||||
const transaction = new Transaction().add(instruction);
|
||||
const { blockhash } = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = wallet.publicKey || undefined;
|
||||
console.log("transaction", transaction);
|
||||
return signSendAndConfirm(wallet, connection, transaction);
|
||||
}
|
||||
|
||||
export async function signSendAndConfirm(
|
||||
wallet: WalletContextState,
|
||||
connection: Connection,
|
||||
transaction: Transaction
|
||||
) {
|
||||
const signed = await wallet.signTransaction(transaction);
|
||||
const txid = await connection.sendRawTransaction(signed.serialize());
|
||||
await connection.confirmTransaction(txid);
|
||||
return txid;
|
||||
}
|
||||
|
||||
export function extractMintAuthorityInfo(
|
||||
account: AccountInfo<Buffer>
|
||||
): string | null {
|
||||
const data = Buffer.from(account.data);
|
||||
const mintInfo = MintLayout.decode(data);
|
||||
|
||||
const uintArray = mintInfo?.mintAuthority;
|
||||
const pubkey = new PublicKey(uintArray);
|
||||
const output = pubkey?.toString();
|
||||
|
||||
return output || null;
|
||||
}
|
||||
|
||||
export async function getMultipleAccountsRPC(
|
||||
connection: Connection,
|
||||
pubkeys: PublicKey[]
|
||||
): Promise<(AccountInfo<Buffer> | null)[]> {
|
||||
return getMultipleAccounts(connection, pubkeys, "finalized");
|
||||
}
|
||||
|
||||
export const getMultipleAccounts = async (
|
||||
connection: any,
|
||||
pubkeys: PublicKey[],
|
||||
commitment: string
|
||||
) => {
|
||||
return (
|
||||
await Promise.all(
|
||||
chunks(pubkeys, 99).map((chunk) =>
|
||||
connection.getMultipleAccountsInfo(chunk, commitment)
|
||||
)
|
||||
)
|
||||
).flat();
|
||||
};
|
||||
|
||||
export function chunks<T>(array: T[], size: number): T[][] {
|
||||
return Array.apply<number, T[], T[][]>(
|
||||
0,
|
||||
new Array(Math.ceil(array.length / size))
|
||||
).map((_, index) => array.slice(index * size, (index + 1) * size));
|
||||
}
|
||||
|
||||
export function shortenAddress(address: string) {
|
||||
return `${address.slice(0, 4)}...${address.slice(-4)}`;
|
||||
}
|
|
@ -3,47 +3,233 @@ import {
|
|||
makeStyles,
|
||||
Typography,
|
||||
Paper,
|
||||
Tab,
|
||||
TextField,
|
||||
Button,
|
||||
} from "@material-ui/core";
|
||||
import { useCallback, useState } from "react";
|
||||
//import { pool_address } from "@certusone/wormhole-sdk/lib/solana/migration/wormhole_migration";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import LogWatcher from "../components/LogWatcher";
|
||||
import SolanaWalletKey from "../components/SolanaWalletKey";
|
||||
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
|
||||
import TabContext from "@material-ui/lab/TabContext";
|
||||
import TabList from "@material-ui/lab/TabList";
|
||||
import TabPanel from "@material-ui/lab/TabPanel";
|
||||
import { MIGRATION_PROGRAM_ADDRESS, SOLANA_URL } from "../utils/consts";
|
||||
import { PublicKey, Connection } from "@solana/web3.js";
|
||||
import { useLogger } from "../contexts/Logger";
|
||||
import { getMultipleAccounts, signSendAndConfirm } from "../utils/solana";
|
||||
import getAuthorityAddress from "@certusone/wormhole-sdk/lib/migration/authorityAddress";
|
||||
import createPoolAccount from "@certusone/wormhole-sdk/lib/migration/createPool";
|
||||
import getPoolAddress from "@certusone/wormhole-sdk/lib/migration/poolAddress";
|
||||
import getFromCustodyAddress from "@certusone/wormhole-sdk/lib/migration/fromCustodyAddress";
|
||||
import getToCustodyAddress from "@certusone/wormhole-sdk/lib/migration/toCustodyAddress";
|
||||
import getShareMintAddress from "@certusone/wormhole-sdk/lib/migration/shareMintAddress";
|
||||
|
||||
const useStyles = makeStyles(() => ({}));
|
||||
const useStyles = makeStyles(() => ({
|
||||
rootContainer: {},
|
||||
mainPaper: {
|
||||
"& > *": {
|
||||
margin: "1rem",
|
||||
},
|
||||
padding: "2rem",
|
||||
},
|
||||
}));
|
||||
|
||||
function Main() {
|
||||
const classes = useStyles();
|
||||
const wallet = useSolanaWallet();
|
||||
const [selectedTab, setSelectedTab] = useState("createPool");
|
||||
const handleChange = useCallback(
|
||||
(event, value) => {
|
||||
setSelectedTab(value);
|
||||
},
|
||||
[setSelectedTab]
|
||||
const logger = useLogger();
|
||||
const connection = new Connection(SOLANA_URL, "finalized");
|
||||
|
||||
const [fromMint, setFromMint] = useState("");
|
||||
const [toMint, setToMint] = useState("");
|
||||
|
||||
const [poolAddress, setPoolAddress] = useState("");
|
||||
const [poolExists, setPoolExists] = useState<boolean | null>(null);
|
||||
const [poolAccountInfo, setPoolAccountInfo] = useState(null);
|
||||
const [shareTokenMint, setShareTokenMint] = useState(null);
|
||||
const [toTokenAccount, setToTokenAccount] = useState(null);
|
||||
const [fromTokenAccount, setFromTokenAccount] = useState(null);
|
||||
const [shareTokenAccount, setShareTokenAccount] = useState(null);
|
||||
|
||||
//these are all the other derived information
|
||||
const [authorityAddress, setAuthorityAddress] = useState(null);
|
||||
const [fromCustodyAddress, setFromCustodyAddress] = useState(null);
|
||||
const [toCustodyAddress, setToCustodyAddress] = useState(null);
|
||||
const [shareMintAddress, setShareMintAddress] = useState(null);
|
||||
|
||||
/*
|
||||
Effects***
|
||||
|
||||
These are generally data fetchers which fire when requisite data populates.
|
||||
|
||||
*/
|
||||
//Retrieve pool address on selectedTokens change
|
||||
useEffect(() => {
|
||||
if (toMint && fromMint) {
|
||||
setPoolAddress("");
|
||||
getPoolAddress(MIGRATION_PROGRAM_ADDRESS, fromMint, toMint).then(
|
||||
(result) => {
|
||||
const key = new PublicKey(result).toString();
|
||||
logger.log("Calculated the pool address at: " + key);
|
||||
setPoolAddress(key);
|
||||
},
|
||||
(error) => logger.log("ERROR, could not calculate pool address.")
|
||||
);
|
||||
}
|
||||
}, [toMint, fromMint, setPoolAddress]);
|
||||
|
||||
//Retrieve the poolAccount every time the pool address changes.
|
||||
useEffect(() => {
|
||||
if (poolAddress) {
|
||||
setPoolAccountInfo(null);
|
||||
setPoolExists(null);
|
||||
try {
|
||||
getMultipleAccounts(
|
||||
connection,
|
||||
[new PublicKey(poolAddress)],
|
||||
"finalized"
|
||||
).then((result) => {
|
||||
if (result.length && result[0] !== null) {
|
||||
setPoolAccountInfo(result[0]);
|
||||
setPoolExists(true);
|
||||
logger.log("Successfully found account info for the pool.");
|
||||
} else if (result.length && result[0] === null) {
|
||||
logger.log("Confirmed that the pool does not exist.");
|
||||
setPoolExists(false);
|
||||
} else {
|
||||
logger.log(
|
||||
"unexpected error in fetching pool address. Please reload and try again"
|
||||
);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
logger.log("Could not fetch pool address");
|
||||
}
|
||||
}
|
||||
}, [poolAddress]);
|
||||
|
||||
useEffect(() => {
|
||||
getAuthorityAddress(MIGRATION_PROGRAM_ADDRESS).then((result: any) =>
|
||||
setAuthorityAddress(result)
|
||||
);
|
||||
|
||||
getToCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||
(result: any) => setToCustodyAddress(result)
|
||||
);
|
||||
getFromCustodyAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||
(result: any) => setFromCustodyAddress(result)
|
||||
);
|
||||
getShareMintAddress(MIGRATION_PROGRAM_ADDRESS, poolAddress).then(
|
||||
(result: any) => setShareMintAddress(result)
|
||||
);
|
||||
}, [poolAddress]);
|
||||
/*
|
||||
End Effects!
|
||||
*/
|
||||
|
||||
/*
|
||||
Actions:
|
||||
|
||||
These are generally onClick actions which the user can perform. They read things off the state, do something,
|
||||
and then potentially update something on the state.
|
||||
|
||||
*/
|
||||
const createPool = async () => {
|
||||
try {
|
||||
const instruction = await createPoolAccount(
|
||||
connection,
|
||||
wallet?.publicKey?.toString() || "",
|
||||
MIGRATION_PROGRAM_ADDRESS,
|
||||
wallet?.publicKey?.toString() || "",
|
||||
fromMint,
|
||||
toMint
|
||||
);
|
||||
|
||||
signSendAndConfirm(wallet, connection, instruction).then(
|
||||
(transaction: any) => {
|
||||
setPoolExists(null); //Set these to null to force a fetch on them
|
||||
setPoolAccountInfo(null);
|
||||
logger.log("Successfully created the pool.");
|
||||
},
|
||||
(error) => {
|
||||
logger.log("Could not create the pool");
|
||||
console.error(error);
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
logger.log("Failed to create the pool.");
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
/*
|
||||
End actions!
|
||||
*/
|
||||
|
||||
const toAndFromSelector = (
|
||||
<>
|
||||
<Typography>
|
||||
Please enter the mint addresses for the 'To' and 'From' tokens you're
|
||||
interested in.
|
||||
</Typography>
|
||||
<TextField
|
||||
value={fromMint}
|
||||
onChange={(event) => setFromMint(event.target.value)}
|
||||
label={"From Token"}
|
||||
fullWidth
|
||||
style={{ display: "block" }}
|
||||
></TextField>
|
||||
<TextField
|
||||
value={toMint}
|
||||
onChange={(event) => setToMint(event.target.value)}
|
||||
label={"To Token"}
|
||||
fullWidth
|
||||
style={{ display: "block" }}
|
||||
></TextField>
|
||||
</>
|
||||
);
|
||||
|
||||
const createPoolButton = (
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => createPool()}
|
||||
disabled={poolExists || !poolAddress}
|
||||
>
|
||||
Click here to instantiate the pool for these tokens.
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
const addLiquidity = (
|
||||
<>
|
||||
<Typography>
|
||||
Add 'to' tokens to this pool, and receive liquidity tokens.
|
||||
</Typography>
|
||||
<TextField
|
||||
value={toMint}
|
||||
onChange={(event) => setToMint(event.target.value)}
|
||||
label={"To Token"}
|
||||
></TextField>
|
||||
</>
|
||||
);
|
||||
|
||||
const mainContent = (
|
||||
<>
|
||||
{toAndFromSelector}
|
||||
{createPoolButton}
|
||||
</>
|
||||
);
|
||||
|
||||
const content = !wallet.publicKey ? (
|
||||
<Typography>Please connect your wallet.</Typography>
|
||||
) : (
|
||||
<TabContext value={selectedTab}>
|
||||
<TabList onChange={handleChange} aria-label="simple tabs example">
|
||||
<Tab label="Create Pool" value="createPool" />
|
||||
<Tab label="Add Liquidity" value="Add Liquidity" />
|
||||
<Tab label="Redeem Liquidity" value="Redeem Liquidity" />
|
||||
</TabList>
|
||||
<TabPanel value="1">Item One</TabPanel>
|
||||
<TabPanel value="2">Item Two</TabPanel>
|
||||
<TabPanel value="3">Item Three</TabPanel>
|
||||
</TabContext>
|
||||
mainContent
|
||||
);
|
||||
|
||||
return (
|
||||
<Container maxWidth="md">
|
||||
<Paper style={{ padding: "3rem" }}>
|
||||
<Container maxWidth="md" className={classes.rootContainer}>
|
||||
<Paper className={classes.mainPaper}>
|
||||
<SolanaWalletKey />
|
||||
{content}
|
||||
</Paper>
|
||||
|
|
|
@ -23,3 +23,11 @@ fs.copyFileSync(
|
|||
"src/solana/token/token_bridge_bg.wasm.d.ts",
|
||||
"lib/solana/token/token_bridge_bg.wasm.d.ts"
|
||||
);
|
||||
fs.copyFileSync(
|
||||
"src/solana/migration/wormhole_migration_bg.wasm",
|
||||
"lib/solana/migration/wormhole_migration_bg.wasm"
|
||||
);
|
||||
fs.copyFileSync(
|
||||
"src/solana/migration/wormhole_migration_bg.wasm.d.ts",
|
||||
"lib/solana/migration/wormhole_migration_bg.wasm.d.ts"
|
||||
);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { ixFromRust } from "../solana";
|
||||
|
||||
export default async function addLiquidity(
|
||||
connection: Connection,
|
||||
payerAddress: string,
|
||||
program_id: string,
|
||||
from_mint: string,
|
||||
to_mint: string,
|
||||
liquidity_token_account: string,
|
||||
lp_share_token_account: string,
|
||||
amount: BigInt
|
||||
) {
|
||||
const { add_liquidity } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
const ix = ixFromRust(
|
||||
add_liquidity(
|
||||
program_id,
|
||||
from_mint,
|
||||
to_mint,
|
||||
liquidity_token_account,
|
||||
lp_share_token_account,
|
||||
amount
|
||||
)
|
||||
);
|
||||
const transaction = new Transaction().add(ix);
|
||||
const { blockhash } = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = new PublicKey(payerAddress);
|
||||
return transaction;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default async function authorityAddress(program_id: string) {
|
||||
const { authority_address } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
return authority_address(program_id);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { ixFromRust } from "../solana";
|
||||
|
||||
export default async function claimShares(
|
||||
connection: Connection,
|
||||
payerAddress: string,
|
||||
program_id: string,
|
||||
from_mint: string,
|
||||
to_mint: string,
|
||||
output_token_account: string,
|
||||
lp_share_token_account: string,
|
||||
amount: BigInt
|
||||
) {
|
||||
const { claim_shares } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
const ix = ixFromRust(
|
||||
claim_shares(
|
||||
program_id,
|
||||
from_mint,
|
||||
to_mint,
|
||||
output_token_account,
|
||||
lp_share_token_account,
|
||||
amount
|
||||
)
|
||||
);
|
||||
const transaction = new Transaction().add(ix);
|
||||
const { blockhash } = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = new PublicKey(payerAddress);
|
||||
return transaction;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { ixFromRust } from "../solana";
|
||||
|
||||
export default async function createPool(
|
||||
connection: Connection,
|
||||
payerAddress: string,
|
||||
program_id: string,
|
||||
payer: string,
|
||||
from_mint: string,
|
||||
to_mint: string
|
||||
) {
|
||||
const { create_pool } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
const ix = ixFromRust(create_pool(program_id, payer, from_mint, to_mint));
|
||||
const transaction = new Transaction().add(ix);
|
||||
const { blockhash } = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = new PublicKey(payerAddress);
|
||||
return transaction;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export default async function fromCustodyAddress(
|
||||
program_id: string,
|
||||
pool: string
|
||||
) {
|
||||
const { from_custody_address } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
return from_custody_address(program_id, pool);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { ixFromRust } from "../solana";
|
||||
|
||||
export default async function migrateTokens(
|
||||
connection: Connection,
|
||||
payerAddress: string,
|
||||
program_id: string,
|
||||
from_mint: string,
|
||||
to_mint: string,
|
||||
input_token_account: string,
|
||||
output_token_account: string,
|
||||
amount: BigInt
|
||||
) {
|
||||
const { migrate_tokens } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
const ix = ixFromRust(
|
||||
migrate_tokens(
|
||||
program_id,
|
||||
from_mint,
|
||||
to_mint,
|
||||
input_token_account,
|
||||
output_token_account,
|
||||
amount
|
||||
)
|
||||
);
|
||||
const transaction = new Transaction().add(ix);
|
||||
const { blockhash } = await connection.getRecentBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = new PublicKey(payerAddress);
|
||||
return transaction;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export default async function parsePool(data: Uint8Array) {
|
||||
const { parse_pool } = await import("../solana/migration/wormhole_migration");
|
||||
return parse_pool(data);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
export default async function poolAddress(
|
||||
program_id: string,
|
||||
from_mint: string,
|
||||
to_mint: string
|
||||
) {
|
||||
const { pool_address } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
return pool_address(program_id, from_mint, to_mint);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export default async function shareMintAddress(
|
||||
program_id: string,
|
||||
pool: string
|
||||
) {
|
||||
const { share_mint_address } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
return share_mint_address(program_id, pool);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export default async function toCustodyAddress(
|
||||
program_id: string,
|
||||
pool: string
|
||||
) {
|
||||
const { to_custody_address } = await import(
|
||||
"../solana/migration/wormhole_migration"
|
||||
);
|
||||
return to_custody_address(program_id, pool);
|
||||
}
|
Loading…
Reference in New Issue