forked from mito-systems/sol-mem-gen
Add api to create a lock
This commit is contained in:
parent
b211e88441
commit
acd60d3ca5
2
Anchor.toml
Normal file
2
Anchor.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[provider]
|
||||
cluster = "mainnet"
|
514
package-lock.json
generated
514
package-lock.json
generated
@ -8,9 +8,11 @@
|
||||
"name": "solana-meme-generator",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@coral-xyz/anchor": "^0.30.1",
|
||||
"@fal-ai/client": "^1.2.1",
|
||||
"@google/generative-ai": "^0.21.0",
|
||||
"@solana/spl-token": "^0.3.8",
|
||||
"@pinata/sdk": "^2.1.0",
|
||||
"@solana/spl-token": "^0.3.11",
|
||||
"@solana/web3.js": "^1.78.4",
|
||||
"big.js": "^6.2.2",
|
||||
"bn.js": "^5.2.0",
|
||||
@ -73,6 +75,64 @@
|
||||
"@chainsafe/is-ip": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@coral-xyz/anchor": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.30.1.tgz",
|
||||
"integrity": "sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ==",
|
||||
"dependencies": {
|
||||
"@coral-xyz/anchor-errors": "^0.30.1",
|
||||
"@coral-xyz/borsh": "^0.30.1",
|
||||
"@noble/hashes": "^1.3.1",
|
||||
"@solana/web3.js": "^1.68.0",
|
||||
"bn.js": "^5.1.2",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.2",
|
||||
"camelcase": "^6.3.0",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"crypto-hash": "^1.3.0",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"pako": "^2.0.3",
|
||||
"snake-case": "^3.0.4",
|
||||
"superstruct": "^0.15.4",
|
||||
"toml": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=11"
|
||||
}
|
||||
},
|
||||
"node_modules/@coral-xyz/anchor-errors": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz",
|
||||
"integrity": "sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@coral-xyz/anchor/node_modules/eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||
},
|
||||
"node_modules/@coral-xyz/anchor/node_modules/superstruct": {
|
||||
"version": "0.15.5",
|
||||
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
|
||||
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
|
||||
},
|
||||
"node_modules/@coral-xyz/borsh": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.30.1.tgz",
|
||||
"integrity": "sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ==",
|
||||
"dependencies": {
|
||||
"bn.js": "^5.1.2",
|
||||
"buffer-layout": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@solana/web3.js": "^1.68.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
@ -638,6 +698,53 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinata/sdk": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@pinata/sdk/-/sdk-2.1.0.tgz",
|
||||
"integrity": "sha512-hkS0tcKtsjf9xhsEBs2Nbey5s+Db7x5rlOH9TaWHBXkJ7IwwOs2xnEDigNaxAHKjYAwcw+m2hzpO5QgOfeF7Zw==",
|
||||
"deprecated": "Please install the new IPFS SDK at pinata-web3. More information at https://docs.pinata.cloud/web3/sdk",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"form-data": "^2.3.3",
|
||||
"is-ipfs": "^0.6.0",
|
||||
"path": "^0.12.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinata/sdk/node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinata/sdk/node_modules/form-data": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz",
|
||||
"integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinata/sdk/node_modules/is-ipfs": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/is-ipfs/-/is-ipfs-0.6.3.tgz",
|
||||
"integrity": "sha512-HyRot1dvLcxImtDqPxAaY1miO6WsiP/z7Yxpg2qpaLWv5UdhAPtLvHJ4kMLM0w8GSl8AFsVF23PHe1LzuWrUlQ==",
|
||||
"dependencies": {
|
||||
"bs58": "^4.0.1",
|
||||
"cids": "~0.7.0",
|
||||
"mafmt": "^7.0.0",
|
||||
"multiaddr": "^7.2.1",
|
||||
"multibase": "~0.6.0",
|
||||
"multihashes": "~0.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@ -1763,6 +1870,14 @@
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-layout": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz",
|
||||
"integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==",
|
||||
"engines": {
|
||||
"node": ">=4.5"
|
||||
}
|
||||
},
|
||||
"node_modules/bufferutil": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz",
|
||||
@ -1872,6 +1987,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-css": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
@ -1955,6 +2081,51 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cids": {
|
||||
"version": "0.7.5",
|
||||
"resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz",
|
||||
"integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"class-is": "^1.1.0",
|
||||
"multibase": "~0.6.0",
|
||||
"multicodec": "^1.0.0",
|
||||
"multihashes": "~0.4.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0",
|
||||
"npm": ">=3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cids/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/class-is": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
|
||||
"integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw=="
|
||||
},
|
||||
"node_modules/clean-stack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
@ -2125,6 +2296,14 @@
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
|
||||
"integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@ -2138,6 +2317,17 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-hash": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz",
|
||||
"integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
@ -2393,6 +2583,15 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
|
||||
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
|
||||
"dependencies": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.7",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||
@ -3992,6 +4191,14 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/ip-regex": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
|
||||
"integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||
@ -4202,6 +4409,17 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-ip": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz",
|
||||
"integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==",
|
||||
"dependencies": {
|
||||
"ip-regex": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-ipfs": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-ipfs/-/is-ipfs-8.0.4.tgz",
|
||||
@ -4714,6 +4932,14 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
@ -4726,6 +4952,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mafmt": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mafmt/-/mafmt-7.1.0.tgz",
|
||||
"integrity": "sha512-vpeo9S+hepT3k2h5iFxzEHvvR0GPBx9uKaErmnRzYNcaKb03DgOArjEMlgG4a9LcuZZ89a3I8xbeto487n26eA==",
|
||||
"dependencies": {
|
||||
"multiaddr": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
@ -4949,11 +5183,226 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/multiaddr": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-7.5.0.tgz",
|
||||
"integrity": "sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw==",
|
||||
"deprecated": "This module is deprecated, please upgrade to @multiformats/multiaddr",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"cids": "~0.8.0",
|
||||
"class-is": "^1.1.0",
|
||||
"is-ip": "^3.1.0",
|
||||
"multibase": "^0.7.0",
|
||||
"varint": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/cids": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz",
|
||||
"integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"buffer": "^5.6.0",
|
||||
"class-is": "^1.1.0",
|
||||
"multibase": "^1.0.0",
|
||||
"multicodec": "^1.0.1",
|
||||
"multihashes": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0",
|
||||
"npm": ">=3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/cids/node_modules/multibase": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz",
|
||||
"integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"base-x": "^3.0.8",
|
||||
"buffer": "^5.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/multibase": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz",
|
||||
"integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"base-x": "^3.0.8",
|
||||
"buffer": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/multihashes": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz",
|
||||
"integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.6.0",
|
||||
"multibase": "^1.0.1",
|
||||
"varint": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multiaddr/node_modules/multihashes/node_modules/multibase": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz",
|
||||
"integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"base-x": "^3.0.8",
|
||||
"buffer": "^5.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multibase": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz",
|
||||
"integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"base-x": "^3.0.8",
|
||||
"buffer": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multibase/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/multicodec": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz",
|
||||
"integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"buffer": "^5.6.0",
|
||||
"varint": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multicodec/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/multiformats": {
|
||||
"version": "13.3.1",
|
||||
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.1.tgz",
|
||||
"integrity": "sha512-QxowxTNwJ3r5RMctoGA5p13w5RbRT2QDkoM+yFlqfLiioBp78nhDjnRLvmSBI9+KAqN4VdgOVWM9c0CHd86m3g=="
|
||||
},
|
||||
"node_modules/multihashes": {
|
||||
"version": "0.4.21",
|
||||
"resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz",
|
||||
"integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"multibase": "^0.7.0",
|
||||
"varint": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multihashes/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/multihashes/node_modules/multibase": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz",
|
||||
"integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==",
|
||||
"deprecated": "This module has been superseded by the multiformats module",
|
||||
"dependencies": {
|
||||
"base-x": "^3.0.8",
|
||||
"buffer": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@ -5073,6 +5522,15 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/no-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||
"dependencies": {
|
||||
"lower-case": "^2.0.2",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.74.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
|
||||
@ -5498,6 +5956,11 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
@ -5528,6 +5991,15 @@
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||
},
|
||||
"node_modules/path": {
|
||||
"version": "0.12.7",
|
||||
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
|
||||
"integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
|
||||
"dependencies": {
|
||||
"process": "^0.11.1",
|
||||
"util": "^0.10.3"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@ -5864,6 +6336,14 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/progress-events": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz",
|
||||
@ -6551,6 +7031,15 @@
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/snake-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
|
||||
"integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
|
||||
"dependencies": {
|
||||
"dot-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
|
||||
@ -7112,6 +7601,11 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toml": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
|
||||
"integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
@ -7646,11 +8140,24 @@
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
|
||||
"dependencies": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/util/node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
@ -7665,6 +8172,11 @@
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/varint": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz",
|
||||
"integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow=="
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
|
@ -9,9 +9,11 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coral-xyz/anchor": "^0.30.1",
|
||||
"@fal-ai/client": "^1.2.1",
|
||||
"@google/generative-ai": "^0.21.0",
|
||||
"@solana/spl-token": "^0.3.8",
|
||||
"@pinata/sdk": "^2.1.0",
|
||||
"@solana/spl-token": "^0.3.11",
|
||||
"@solana/web3.js": "^1.78.4",
|
||||
"big.js": "^6.2.2",
|
||||
"bn.js": "^5.2.0",
|
||||
|
@ -88,6 +88,7 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||
|
||||
// Extract the image URL from the response
|
||||
const imageUrl = result.data?.images?.[0]?.url
|
||||
console.log(imageUrl);
|
||||
|
||||
if (!imageUrl) {
|
||||
console.error('No image URL in response:', result)
|
||||
|
172
src/app/api/lock/route.ts
Normal file
172
src/app/api/lock/route.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { Connection, Keypair, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction, PublicKey } from "@solana/web3.js";
|
||||
import { createLock } from "../../../utils/create-lock";
|
||||
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import assert from "assert";
|
||||
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
|
||||
import { BN, min } from "bn.js";
|
||||
|
||||
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL);
|
||||
|
||||
const connection = new Connection(process.env.NEXT_PUBLIC_SOLANA_RPC_URL);
|
||||
const MTM_MINT_ADDRESS = process.env.NEXT_PUBLIC_MTM_TOKEN_MINT;
|
||||
|
||||
function isParsedInstruction(
|
||||
instruction: ParsedInstruction | PartiallyDecodedInstruction
|
||||
): instruction is ParsedInstruction {
|
||||
return (instruction as ParsedInstruction).parsed !== undefined;
|
||||
}
|
||||
|
||||
async function extractMTMTransferDetails(
|
||||
connection: Connection,
|
||||
signature: string,
|
||||
mtmMintAddress: string // Mint address of the MTM token
|
||||
) {
|
||||
try {
|
||||
// Fetch the transaction details using the signature
|
||||
const transaction: ParsedTransactionWithMeta | null = await connection.getParsedTransaction(signature, {
|
||||
maxSupportedTransactionVersion: 0, // Ensure compatibility with legacy transactions
|
||||
});
|
||||
|
||||
if (!transaction) {
|
||||
throw new Error('Transaction not found');
|
||||
}
|
||||
|
||||
// Extract the "from", "to", and "amount" for the MTM token transfer
|
||||
let fromAddress: string | null = null;
|
||||
let toAddress: string | null = null;
|
||||
let tokenAmount: number | null = null;
|
||||
|
||||
// Function to process instructions
|
||||
const processInstructions = (instructions: ParsedInstruction[]) => {
|
||||
instructions.forEach((instruction: ParsedInstruction) => {
|
||||
if (instruction.programId.equals(new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'))) {
|
||||
// Check if the instruction is a transfer instruction
|
||||
if (instruction.parsed.type === 'transfer' || instruction.parsed.type === 'transferChecked') {
|
||||
const parsedInfo = instruction.parsed.info;
|
||||
const mint = parsedInfo.mint;
|
||||
|
||||
// Check if the mint address matches the provided MTM mint address
|
||||
if (mint === mtmMintAddress) {
|
||||
fromAddress = parsedInfo.source;
|
||||
toAddress = parsedInfo.destination;
|
||||
tokenAmount = parsedInfo.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Filter out PartiallyDecodedInstruction and process only ParsedInstruction
|
||||
const parsedInstructions = transaction.transaction.message.instructions.filter(isParsedInstruction);
|
||||
|
||||
// Process top-level instructions
|
||||
processInstructions(parsedInstructions);
|
||||
|
||||
// Process inner instructions (if any)
|
||||
if (transaction.meta?.innerInstructions) {
|
||||
transaction.meta.innerInstructions.forEach((inner) => {
|
||||
const innerParsedInstructions = inner.instructions.filter(isParsedInstruction);
|
||||
processInstructions(innerParsedInstructions);
|
||||
});
|
||||
}
|
||||
|
||||
if (!fromAddress || !toAddress || !tokenAmount) {
|
||||
throw new Error('No matching MTM token transfer found in the transaction');
|
||||
}
|
||||
|
||||
return { fromAddress, toAddress, tokenAmount };
|
||||
} catch (error) {
|
||||
console.error('Error extracting MTM transfer details:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
// Get signature from URL params
|
||||
const { searchParams } = new URL(req.url);
|
||||
const signature = searchParams.get('signature') || '4HBtnoNUuMGpmbhD9cPiJtbxkhux31pfZs3HYud5eopAU69RaC4UbJsYdj83eafFxV6eH8pSaRgqELrwyjrWp7yz';
|
||||
let amount = new BN(0);
|
||||
|
||||
if (!signature) {
|
||||
return NextResponse.json(
|
||||
{ error: "Transaction signature is required" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!MTM_MINT_ADDRESS) {
|
||||
return NextResponse.json(
|
||||
{ error: "MTM_MINT_ADDRESS environment variable is not set" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Extract transaction details
|
||||
// const result = await extractMTMTransferDetails(
|
||||
// connection,
|
||||
// signature,
|
||||
// MTM_MINT_ADDRESS
|
||||
// );
|
||||
|
||||
// if (!result) {
|
||||
// return NextResponse.json(
|
||||
// { error: "Failed to extract transaction details" },
|
||||
// { status: 500 }
|
||||
// );
|
||||
// }
|
||||
|
||||
// console.log({ result });
|
||||
|
||||
// // Validate extracted values
|
||||
// if (!result.fromAddress || result.tokenAmount <= 0) {
|
||||
// return NextResponse.json(
|
||||
// { error: "Invalid transaction details extracted" },
|
||||
// { status: 400 }
|
||||
// );
|
||||
// }
|
||||
|
||||
assert(process.env.USER_PRIVATE_KEY, 'USER_PRIVATE_KEY is required');
|
||||
assert(process.env.CLIFF_TIME, 'CLIFF_TIME is required');
|
||||
|
||||
const USER_PRIVATE_KEY = process.env.USER_PRIVATE_KEY;
|
||||
const CLIFF_TIME = process.env.CLIFF_TIME;
|
||||
|
||||
const duration = new BN(CLIFF_TIME).add(new BN(Math.floor(Date.now() / 1000)));
|
||||
const tokenLockerKeypair = Keypair.fromSecretKey(bs58.decode(USER_PRIVATE_KEY));
|
||||
const recipientPublicKey = new PublicKey('Bnnq8n3rRKZe8NJAYn4vBkxp1v8Bnc6zXpUPpDeujCu');
|
||||
|
||||
amount = amount.add(new BN(1000000));
|
||||
|
||||
// Call createLock function with extracted values
|
||||
let escrow;
|
||||
try {
|
||||
escrow = await createLock(tokenLockerKeypair, recipientPublicKey, duration, amount);
|
||||
} catch (error) {
|
||||
console.error('Error creating lock:', error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to create lock" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log({ escrow });
|
||||
|
||||
// Return successful response
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
sender: recipientPublicKey,
|
||||
amount: amount,
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('API route error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
254
src/locker-utils/index.ts
Normal file
254
src/locker-utils/index.ts
Normal file
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Methods from jup-lock:
|
||||
* - createLockerProgram
|
||||
* - deriveEscrow
|
||||
* - createVestingPlanV2
|
||||
* Reference: https://github.com/jup-ag/jup-lock/blob/main/tests/locker_utils/index.ts
|
||||
*/
|
||||
|
||||
import assert from 'assert';
|
||||
import 'dotenv/config';
|
||||
|
||||
import {
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
getAssociatedTokenAddressSync,
|
||||
TOKEN_2022_PROGRAM_ID,
|
||||
TOKEN_PROGRAM_ID,
|
||||
} from '@solana/spl-token';
|
||||
import {
|
||||
AnchorProvider,
|
||||
BN,
|
||||
Program,
|
||||
Wallet,
|
||||
web3,
|
||||
workspace,
|
||||
} from '@coral-xyz/anchor';
|
||||
import { AccountMeta, Connection, SendTransactionError } from '@solana/web3.js';
|
||||
|
||||
// TODO: Generate type file from IDL json
|
||||
import { Locker } from '../../target/types/locker';
|
||||
import { TokenExtensionUtil } from './token-2022/token-extensions';
|
||||
import {
|
||||
OptionRemainingAccountsInfoData,
|
||||
RemainingAccountsBuilder,
|
||||
RemainingAccountsType,
|
||||
} from './token-2022/remaining-accounts';
|
||||
|
||||
assert(process.env.RPC_ENDPOINT);
|
||||
|
||||
const connection = new Connection(process.env.RPC_ENDPOINT);
|
||||
|
||||
const ESCROW_USE_SPL_TOKEN = 0;
|
||||
|
||||
const MEMO_PROGRAM = new web3.PublicKey(
|
||||
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
|
||||
);
|
||||
|
||||
export function createLockerProgram(wallet: Wallet): Program<Locker> {
|
||||
const provider = new AnchorProvider(connection, wallet, {
|
||||
maxRetries: 3,
|
||||
});
|
||||
provider.opts.commitment = 'confirmed';
|
||||
|
||||
return workspace.Locker as Program<Locker>;
|
||||
}
|
||||
|
||||
export function deriveEscrow(base: web3.PublicKey, programId: web3.PublicKey) {
|
||||
return web3.PublicKey.findProgramAddressSync(
|
||||
[Buffer.from('escrow'), base.toBuffer()],
|
||||
programId
|
||||
);
|
||||
}
|
||||
|
||||
export interface CreateVestingPlanParams {
|
||||
ownerKeypair: web3.Keypair;
|
||||
tokenMint: web3.PublicKey;
|
||||
isAssertion: boolean;
|
||||
vestingStartTime: BN;
|
||||
cliffTime: BN;
|
||||
frequency: BN;
|
||||
cliffUnlockAmount: BN;
|
||||
amountPerPeriod: BN;
|
||||
numberOfPeriod: BN;
|
||||
recipient: web3.PublicKey;
|
||||
updateRecipientMode: number;
|
||||
cancelMode: number;
|
||||
tokenProgram?: web3.PublicKey;
|
||||
}
|
||||
|
||||
// V2 instructions
|
||||
export async function createVestingPlanV2(params: CreateVestingPlanParams) {
|
||||
let {
|
||||
tokenMint,
|
||||
ownerKeypair,
|
||||
vestingStartTime,
|
||||
cliffTime,
|
||||
frequency,
|
||||
cliffUnlockAmount,
|
||||
amountPerPeriod,
|
||||
numberOfPeriod,
|
||||
recipient,
|
||||
updateRecipientMode,
|
||||
cancelMode,
|
||||
tokenProgram,
|
||||
} = params;
|
||||
|
||||
const program = createLockerProgram(new Wallet(ownerKeypair));
|
||||
|
||||
const baseKP = web3.Keypair.generate();
|
||||
|
||||
let [escrow] = deriveEscrow(baseKP.publicKey, program.programId);
|
||||
|
||||
const senderToken = getAssociatedTokenAddressSync(
|
||||
tokenMint,
|
||||
ownerKeypair.publicKey,
|
||||
false,
|
||||
tokenProgram,
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
);
|
||||
|
||||
const escrowToken = getAssociatedTokenAddressSync(
|
||||
tokenMint,
|
||||
escrow,
|
||||
true,
|
||||
tokenProgram,
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
);
|
||||
|
||||
let remainingAccountsInfo = null;
|
||||
let remainingAccounts: AccountMeta[] = [];
|
||||
if (tokenProgram == TOKEN_2022_PROGRAM_ID) {
|
||||
let inputTransferHookAccounts =
|
||||
await TokenExtensionUtil.getExtraAccountMetasForTransferHook(
|
||||
program.provider.connection,
|
||||
tokenMint,
|
||||
senderToken,
|
||||
escrowToken,
|
||||
ownerKeypair.publicKey,
|
||||
TOKEN_2022_PROGRAM_ID
|
||||
);
|
||||
|
||||
[remainingAccountsInfo, remainingAccounts] = new RemainingAccountsBuilder()
|
||||
.addSlice(
|
||||
RemainingAccountsType.TransferHookEscrow,
|
||||
inputTransferHookAccounts
|
||||
)
|
||||
.build() as [OptionRemainingAccountsInfoData, AccountMeta[]];
|
||||
}
|
||||
|
||||
assert(tokenProgram);
|
||||
|
||||
try {
|
||||
const transaction = await program.methods
|
||||
.createVestingEscrowV2(
|
||||
{
|
||||
vestingStartTime,
|
||||
cliffTime,
|
||||
frequency,
|
||||
cliffUnlockAmount,
|
||||
amountPerPeriod,
|
||||
numberOfPeriod,
|
||||
updateRecipientMode,
|
||||
cancelMode,
|
||||
},
|
||||
remainingAccountsInfo
|
||||
)
|
||||
.accounts({
|
||||
base: baseKP.publicKey,
|
||||
senderToken,
|
||||
escrowToken,
|
||||
recipient,
|
||||
tokenMint,
|
||||
sender: ownerKeypair.publicKey,
|
||||
tokenProgram,
|
||||
systemProgram: web3.SystemProgram.programId,
|
||||
escrow,
|
||||
// TODO: Fix type error for escrowToken
|
||||
} as any)
|
||||
.remainingAccounts(remainingAccounts ? remainingAccounts : [])
|
||||
.preInstructions([
|
||||
createAssociatedTokenAccountInstruction(
|
||||
ownerKeypair.publicKey,
|
||||
escrowToken,
|
||||
escrow,
|
||||
tokenMint,
|
||||
tokenProgram,
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
),
|
||||
])
|
||||
.signers([baseKP, ownerKeypair])
|
||||
.rpc();
|
||||
|
||||
return escrow;
|
||||
} catch (error) {
|
||||
if (error instanceof SendTransactionError) {
|
||||
console.error('Transaction failed:', error.message);
|
||||
console.error('Logs:', error.logs);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ClaimTokenParamsV2 {
|
||||
isAssertion: boolean;
|
||||
escrow: web3.PublicKey;
|
||||
recipient: web3.Keypair;
|
||||
maxAmount: BN;
|
||||
recipientToken: web3.PublicKey;
|
||||
tokenProgram: web3.PublicKey;
|
||||
}
|
||||
|
||||
export async function claimTokenV2(params: ClaimTokenParamsV2) {
|
||||
let { isAssertion, escrow, recipient, maxAmount, recipientToken } = params;
|
||||
const program = createLockerProgram(new Wallet(recipient));
|
||||
const escrowState = await program.account.vestingEscrow.fetch(escrow);
|
||||
const tokenProgram =
|
||||
escrowState.tokenProgramFlag == ESCROW_USE_SPL_TOKEN
|
||||
? TOKEN_PROGRAM_ID
|
||||
: TOKEN_2022_PROGRAM_ID;
|
||||
|
||||
const escrowToken = getAssociatedTokenAddressSync(
|
||||
escrowState.tokenMint,
|
||||
escrow,
|
||||
true,
|
||||
tokenProgram,
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
);
|
||||
|
||||
let remainingAccountsInfo = null;
|
||||
let remainingAccounts: AccountMeta[] | undefined = [];
|
||||
if (tokenProgram == TOKEN_2022_PROGRAM_ID) {
|
||||
let claimTransferHookAccounts =
|
||||
await TokenExtensionUtil.getExtraAccountMetasForTransferHook(
|
||||
program.provider.connection,
|
||||
escrowState.tokenMint,
|
||||
escrowToken,
|
||||
recipientToken,
|
||||
escrow,
|
||||
TOKEN_2022_PROGRAM_ID
|
||||
);
|
||||
|
||||
[remainingAccountsInfo, remainingAccounts] = new RemainingAccountsBuilder()
|
||||
.addSlice(
|
||||
RemainingAccountsType.TransferHookEscrow,
|
||||
claimTransferHookAccounts
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
const tx = await program.methods
|
||||
.claimV2(maxAmount, remainingAccountsInfo)
|
||||
.accounts({
|
||||
tokenProgram,
|
||||
tokenMint: escrowState.tokenMint,
|
||||
memoProgram: MEMO_PROGRAM,
|
||||
escrow,
|
||||
escrowToken,
|
||||
recipient: recipient.publicKey,
|
||||
recipientToken,
|
||||
} as any)
|
||||
.remainingAccounts(remainingAccounts ? remainingAccounts : [])
|
||||
.signers([recipient])
|
||||
.rpc();
|
||||
}
|
50
src/locker-utils/token-2022/remaining-accounts.ts
Normal file
50
src/locker-utils/token-2022/remaining-accounts.ts
Normal file
@ -0,0 +1,50 @@
|
||||
// Reference: https://github.com/jup-ag/jup-lock/blob/main/tests/locker_utils/index.ts
|
||||
|
||||
import { AccountMeta } from '@solana/web3.js';
|
||||
|
||||
export enum RemainingAccountsType {
|
||||
TransferHookEscrow = 'transferHookEscrow',
|
||||
}
|
||||
|
||||
type RemainingAccountsAnchorType = { transferHookEscrow: {} };
|
||||
|
||||
export type RemainingAccountsSliceData = {
|
||||
accountsType: RemainingAccountsAnchorType;
|
||||
length: number;
|
||||
};
|
||||
|
||||
export type RemainingAccountsInfoData = {
|
||||
slices: RemainingAccountsSliceData[];
|
||||
};
|
||||
|
||||
// Option<RemainingAccountsInfoData> on Rust
|
||||
// null is treated as None in Rust. undefined doesn't work.
|
||||
export type OptionRemainingAccountsInfoData = RemainingAccountsInfoData | null;
|
||||
|
||||
export class RemainingAccountsBuilder {
|
||||
private remainingAccounts: AccountMeta[] = [];
|
||||
private slices: RemainingAccountsSliceData[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
addSlice(
|
||||
accountsType: RemainingAccountsType,
|
||||
accounts?: AccountMeta[]
|
||||
): this {
|
||||
if (!accounts || accounts.length === 0) return this;
|
||||
|
||||
this.slices.push({
|
||||
accountsType: { [accountsType]: {} } as RemainingAccountsAnchorType,
|
||||
length: accounts.length,
|
||||
});
|
||||
this.remainingAccounts.push(...accounts);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): [OptionRemainingAccountsInfoData, AccountMeta[] | undefined] {
|
||||
return this.slices.length === 0
|
||||
? [null, undefined]
|
||||
: [{ slices: this.slices }, this.remainingAccounts];
|
||||
}
|
||||
}
|
57
src/locker-utils/token-2022/token-extensions.ts
Normal file
57
src/locker-utils/token-2022/token-extensions.ts
Normal file
@ -0,0 +1,57 @@
|
||||
// Reference: https://github.com/jup-ag/jup-lock/blob/main/tests/locker_utils/index.ts
|
||||
|
||||
import {
|
||||
AccountMeta,
|
||||
Connection,
|
||||
PublicKey,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js';
|
||||
import {
|
||||
addExtraAccountsToInstruction,
|
||||
getMint,
|
||||
getTransferHook,
|
||||
TOKEN_2022_PROGRAM_ID,
|
||||
} from '@solana/spl-token';
|
||||
|
||||
export class TokenExtensionUtil {
|
||||
public static async getExtraAccountMetasForTransferHook(
|
||||
connection: Connection,
|
||||
tokenMint: PublicKey,
|
||||
source: PublicKey,
|
||||
destination: PublicKey,
|
||||
owner: PublicKey,
|
||||
tokenProgram: PublicKey
|
||||
): Promise<AccountMeta[] | undefined> {
|
||||
let mint = await getMint(connection, tokenMint, 'confirmed', tokenProgram);
|
||||
const transferHook = getTransferHook(mint);
|
||||
|
||||
if (!transferHook) return undefined;
|
||||
|
||||
const instruction = new TransactionInstruction({
|
||||
programId: TOKEN_2022_PROGRAM_ID,
|
||||
keys: [
|
||||
{ pubkey: source, isSigner: false, isWritable: false },
|
||||
{
|
||||
pubkey: tokenMint,
|
||||
isSigner: false,
|
||||
isWritable: false,
|
||||
},
|
||||
{ pubkey: destination, isSigner: false, isWritable: false },
|
||||
{ pubkey: owner, isSigner: false, isWritable: false },
|
||||
{ pubkey: owner, isSigner: false, isWritable: false },
|
||||
],
|
||||
});
|
||||
|
||||
// Note:
|
||||
await addExtraAccountsToInstruction(
|
||||
connection,
|
||||
instruction,
|
||||
tokenMint,
|
||||
'confirmed',
|
||||
transferHook.programId,
|
||||
);
|
||||
|
||||
const extraAccountMetas = instruction.keys.slice(5);
|
||||
return extraAccountMetas.length > 0 ? extraAccountMetas : undefined;
|
||||
}
|
||||
}
|
95
src/utils/create-lock.ts
Normal file
95
src/utils/create-lock.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import assert from 'assert';
|
||||
import BN from 'bn.js';
|
||||
import 'dotenv/config';
|
||||
import bs58 from 'bs58';
|
||||
|
||||
import * as anchor from "@coral-xyz/anchor";
|
||||
import {
|
||||
TOKEN_PROGRAM_ID,
|
||||
} from "@solana/spl-token";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
|
||||
import { createVestingPlanV2 } from '../locker-utils';
|
||||
|
||||
assert(process.env.RPC_ENDPOINT);
|
||||
assert(process.env.USER_PRIVATE_KEY);
|
||||
//assert(process.env.RECIPIENT_PUBLIC_KEY);
|
||||
assert(process.env.MTM_MINT);
|
||||
|
||||
const RPC_ENDPOINT= process.env.RPC_ENDPOINT;
|
||||
const MTM_MINT = process.env.MTM_MINT;
|
||||
const USER_PRIVATE_KEY = process.env.USER_PRIVATE_KEY;
|
||||
|
||||
const userKP = anchor.web3.Keypair.fromSecretKey(bs58.decode(USER_PRIVATE_KEY));
|
||||
|
||||
const connection = new Connection(RPC_ENDPOINT);
|
||||
const token = new PublicKey(MTM_MINT);
|
||||
|
||||
const provider = new anchor.AnchorProvider(
|
||||
connection,
|
||||
new anchor.Wallet(userKP),
|
||||
// Commitment level required for simulating transaction
|
||||
{ preflightCommitment: 'processed' }
|
||||
);
|
||||
|
||||
anchor.setProvider(provider);
|
||||
|
||||
export async function getMTMBalance (senderKeypair: anchor.web3.Keypair): Promise<BN> {
|
||||
const mintPublicKey = new PublicKey(MTM_MINT);
|
||||
const publicKey = senderKeypair.publicKey;
|
||||
const tokenAccounts = await connection.getTokenAccountsByOwner(publicKey, { mint: mintPublicKey });
|
||||
|
||||
let balance = new BN(0);
|
||||
for (const tokenAccount of tokenAccounts.value) {
|
||||
const accountInfo = await connection.getParsedAccountInfo(
|
||||
tokenAccount.pubkey,
|
||||
"confirmed"
|
||||
);
|
||||
|
||||
if (!accountInfo.value || Buffer.isBuffer(accountInfo.value.data)) {
|
||||
console.warn(
|
||||
`Token account ${tokenAccount.pubkey.toBase58()} data is not parsed.`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const tokenAmount =
|
||||
(accountInfo.value.data as any).parsed?.info?.tokenAmount?.amount || "0";
|
||||
balance = balance.add(new BN(tokenAmount));
|
||||
}
|
||||
|
||||
return balance;
|
||||
};
|
||||
|
||||
export async function createLock(tokenLockerKeypair: anchor.web3.Keypair, recipientPubKey: anchor.web3.PublicKey, duration: BN, balance: BN): Promise<anchor.web3.PublicKey | void> {
|
||||
//const balance = await getMTMBalance(tokenLockerKeypair);
|
||||
|
||||
if (balance.eq(new BN(0))) {
|
||||
console.log('No balance available to create lock, skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Creating a lock...');
|
||||
|
||||
const escrow = await createVestingPlanV2({
|
||||
ownerKeypair: tokenLockerKeypair,
|
||||
vestingStartTime: new BN(Math.floor(Date.now() / 1000) - 60), // Start immediately
|
||||
tokenMint: token,
|
||||
isAssertion: true,
|
||||
cliffTime: duration,
|
||||
frequency: new BN(1), // Not needed since full unlock happens at cliff
|
||||
cliffUnlockAmount: balance, // The entire amount should be released at cliff
|
||||
amountPerPeriod: new BN(0), // No tokens should be released before cliff
|
||||
numberOfPeriod: new BN(1), // Only release tokens once
|
||||
recipient: recipientPubKey,
|
||||
updateRecipientMode: 0,
|
||||
cancelMode: 1,
|
||||
tokenProgram: TOKEN_PROGRAM_ID,
|
||||
});
|
||||
|
||||
if (escrow) {
|
||||
console.log('Lock created successfully: ', escrow.toString());
|
||||
}
|
||||
|
||||
return escrow;
|
||||
}
|
@ -1,28 +1,49 @@
|
||||
import { PinataSDK } from 'pinata-web3';
|
||||
import PinataClient from "@pinata/sdk"
|
||||
import 'dotenv/config';
|
||||
import assert from 'assert';
|
||||
|
||||
import { FluxGenerationResult } from '../services/fluxService';
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
|
||||
assert(process.env.PINATA_JWT, "PINATA_JWT is required");
|
||||
assert(process.env.PINATA_GATEWAY, "PINATA_GATEWAY is required");
|
||||
assert(process.env.PINATA_API_KEY, "PINATA_API_KEY is required");
|
||||
assert(process.env.PINATA_SECRET_KEY, "PINATA_SECRET_KEY is required");
|
||||
assert(process.env.PINATA_JWT, "PINATA_SECRET_KEY is required");
|
||||
assert(process.env.PINATA_GATEWAY);
|
||||
|
||||
const pinata = new PinataSDK({
|
||||
pinataJwt: process.env.PINATA_JWT,
|
||||
pinataGateway: process.env.PINATA_GATEWAY,
|
||||
const pinata = new PinataClient({
|
||||
pinataApiKey: process.env.PINATA_API_KEY,
|
||||
pinataSecretApiKey: process.env.PINATA_SECRET_KEY,
|
||||
pinataJWTKey: process.env.PINATA_JWT
|
||||
});
|
||||
|
||||
|
||||
export async function uploadToPinata(imageUrl: string): Promise<FluxGenerationResult> {
|
||||
try {
|
||||
const upload = await pinata.upload.url(imageUrl);
|
||||
const response = await axios.get(imageUrl, {
|
||||
responseType: 'arraybuffer'
|
||||
});
|
||||
|
||||
const publicURL = await pinata.gateways.convert(upload.IpfsHash);
|
||||
// Create form data
|
||||
const formData = new FormData();
|
||||
formData.append('file', Buffer.from(response.data), {
|
||||
filename: `image-${Date.now()}.jpg`,
|
||||
contentType: 'image/jpeg',
|
||||
});
|
||||
|
||||
// Use the correct Pinata method for file upload
|
||||
const result = await pinata.pinFileToIPFS(formData);
|
||||
|
||||
if (!result.IpfsHash) {
|
||||
throw new Error('IPFS hash not received from Pinata');
|
||||
}
|
||||
|
||||
const publicURL = `${process.env.PINATA_GATEWAY}/ipfs/${result.IpfsHash}`;
|
||||
|
||||
return { imageUrl: publicURL };
|
||||
} catch (error) {
|
||||
console.error('Error uploading to Pinata:', error)
|
||||
console.error('Error uploading to Pinata:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : 'Upload failed'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
3143
target/idl/locker.json
Normal file
3143
target/idl/locker.json
Normal file
File diff suppressed because it is too large
Load Diff
3149
target/types/locker.ts
Normal file
3149
target/types/locker.ts
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user