From 3a120b8348fa522082d9e19b2b74f66eb031e6a3 Mon Sep 17 00:00:00 2001 From: Tejas Badadare Date: Mon, 17 Mar 2025 11:19:15 -0700 Subject: [PATCH] feat: add twap demo to send-usd example app --- package-lock.json | 6 + .../solana/send_usd/app/package-lock.json | 188 +++++++++++------- price_feeds/solana/send_usd/app/package.json | 8 +- price_feeds/solana/send_usd/app/src/App.tsx | 167 ++++++++++++---- .../send_usd/app/src/idl/send_usd_app.json | 44 +++- .../send_usd/app/src/idl/send_usd_app.ts | 76 ++++++- .../solana/send_usd/program/Cargo.lock | 4 +- .../solana/send_usd/program/Cargo.toml | 2 +- .../solana/send_usd/program/src/lib.rs | 66 ++++-- 9 files changed, 424 insertions(+), 137 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6e4dcf2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "pyth-examples", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/price_feeds/solana/send_usd/app/package-lock.json b/price_feeds/solana/send_usd/app/package-lock.json index 313fae1..944f4d9 100644 --- a/price_feeds/solana/send_usd/app/package-lock.json +++ b/price_feeds/solana/send_usd/app/package-lock.json @@ -1,15 +1,15 @@ { "name": "send_usd", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "send_usd", - "version": "0.1.0", + "version": "0.2.0", "dependencies": { - "@pythnetwork/price-service-client": "^1.8.2", - "@pythnetwork/pyth-solana-receiver": "^0.7.0", + "@pythnetwork/hermes-client": "^2.0.0", + "@pythnetwork/pyth-solana-receiver": "^0.10.0", "@solana/wallet-adapter-base": "^0.9.23", "@solana/wallet-adapter-react": "^0.15.35", "@solana/wallet-adapter-react-ui": "^0.9.35", @@ -2363,6 +2363,7 @@ "version": "0.29.0", "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz", "integrity": "sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==", + "license": "(MIT OR Apache-2.0)", "dependencies": { "@coral-xyz/borsh": "^0.29.0", "@noble/hashes": "^1.3.1", @@ -2387,6 +2388,7 @@ "version": "0.29.0", "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz", "integrity": "sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==", + "license": "Apache-2.0", "dependencies": { "bn.js": "^5.1.2", "buffer-layout": "^1.2.0" @@ -2924,9 +2926,10 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.8.tgz", - "integrity": "sha512-vYVqYzHicDqyKB+NQhAc54I1QWCBLCrYG6unqOIcBTHx+7x8C9lcoLj3KVJXs2VB4lUbpWY+Kk9NipcbXYWmvg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.0.tgz", + "integrity": "sha512-pMuxInZjUnUkgMT2QLZclRqwk2ykJbIU05aZgPgJYXEpN9+2I7z7aNwcjWZSycRPl232FfhPszyBFJyOxTHNog==", + "license": "Apache-2.0", "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" @@ -2939,6 +2942,7 @@ "version": "0.7.13", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "license": "Apache-2.0", "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", @@ -2953,9 +2957,10 @@ } }, "node_modules/@grpc/proto-loader/node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz", + "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", + "license": "Apache-2.0" }, "node_modules/@hapi/hoek": { "version": "9.3.0", @@ -3499,6 +3504,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" @@ -3808,7 +3814,8 @@ "type": "individual", "url": "https://paulmillr.com/funding/" } - ] + ], + "license": "MIT" }, "node_modules/@noble/hashes": { "version": "1.4.0", @@ -4326,44 +4333,44 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, - "node_modules/@pythnetwork/price-service-client": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@pythnetwork/price-service-client/-/price-service-client-1.9.0.tgz", - "integrity": "sha512-SLm3IFcfmy9iMqHeT4Ih6qMNZhJEefY14T9yTlpsH2D/FE5+BaGGnfcexUifVlfH6M7mwRC4hEFdNvZ6ebZjJg==", + "node_modules/@pythnetwork/hermes-client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@pythnetwork/hermes-client/-/hermes-client-2.0.0.tgz", + "integrity": "sha512-8ZbCrO5NSlsu1zauIJjZv0sPR3qF9uzgCpBpAPSBGBjwKP0T3TdIRfuSzf9mpzrqf+b7QUqNVNLWZqgN7nlREw==", + "license": "Apache-2.0", "dependencies": { - "@pythnetwork/price-service-sdk": "*", - "@types/ws": "^8.5.3", - "axios": "^1.5.1", - "axios-retry": "^3.8.0", - "isomorphic-ws": "^4.0.1", - "ts-log": "^2.2.4", - "ws": "^8.6.0" + "@zodios/core": "^10.9.6", + "eventsource": "^3.0.5", + "zod": "^3.23.8" } }, "node_modules/@pythnetwork/price-service-sdk": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@pythnetwork/price-service-sdk/-/price-service-sdk-1.7.1.tgz", - "integrity": "sha512-xr2boVXTyv1KUt/c6llUTfbv2jpud99pWlMJbFaHGUBoygQsByuy7WbjIJKZ+0Blg1itLZl0Lp/pJGGg8SdJoQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@pythnetwork/price-service-sdk/-/price-service-sdk-1.8.0.tgz", + "integrity": "sha512-tFZ1thj3Zja06DzPIX2dEWSi7kIfIyqreoywvw5NQ3Z1pl5OJHQGMEhxt6Li3UCGSp2ooYZS9wl8/8XfrfrNSA==", + "license": "Apache-2.0", "dependencies": { "bn.js": "^5.2.1" } }, "node_modules/@pythnetwork/pyth-solana-receiver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@pythnetwork/pyth-solana-receiver/-/pyth-solana-receiver-0.7.0.tgz", - "integrity": "sha512-OoEAHh92RPRdKkfjkcKGrjC+t0F3SEL754iKFmixN9zyS8pIfZSVfFntmkHa9pWmqEMxdx/i925a8B5ny8Tuvg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@pythnetwork/pyth-solana-receiver/-/pyth-solana-receiver-0.10.0.tgz", + "integrity": "sha512-uhdjmWUWuxq4lfW19k75uBsoevx9ktIt1YOjNQ8TEiwPpXl7vTpArymROzGRl1h7FlGgjgHJm7AefguLEo2Uxg==", + "license": "Apache-2.0", "dependencies": { "@coral-xyz/anchor": "^0.29.0", "@noble/hashes": "^1.4.0", - "@pythnetwork/price-service-sdk": ">=1.6.0", - "@pythnetwork/solana-utils": "*", + "@pythnetwork/price-service-sdk": "1.8.0", + "@pythnetwork/solana-utils": "0.4.4", "@solana/web3.js": "^1.90.0" } }, "node_modules/@pythnetwork/solana-utils": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@pythnetwork/solana-utils/-/solana-utils-0.4.1.tgz", - "integrity": "sha512-xls6Ad1ibG+iByAiXsZjb39AlmYB2cvWnUiiQAjbmNYlQpajmz1bKJ4HhgfylZljE6FGsK4trSCf2YRo3nXBoQ==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@pythnetwork/solana-utils/-/solana-utils-0.4.4.tgz", + "integrity": "sha512-kE+q6kTfoXIaBXAtXKdpsjLlxvME2PQHFf3hxADYr8akV7nbpZc2u5vn6dVNN5qUbH+Pk5R/1VkxdfhoLX3l/w==", + "license": "Apache-2.0", "dependencies": { "@coral-xyz/anchor": "^0.29.0", "@solana/web3.js": "^1.90.0", @@ -4372,14 +4379,16 @@ } }, "node_modules/@pythnetwork/solana-utils/node_modules/base-x": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", - "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", + "integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==", + "license": "MIT" }, "node_modules/@pythnetwork/solana-utils/node_modules/bs58": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "license": "MIT", "dependencies": { "base-x": "^4.0.0" } @@ -9474,6 +9483,16 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, + "node_modules/@zodios/core": { + "version": "10.9.6", + "resolved": "https://registry.npmjs.org/@zodios/core/-/core-10.9.6.tgz", + "integrity": "sha512-aH4rOdb3AcezN7ws8vDgBfGboZMk2JGGzEq/DtW65MhnRxyTGRuLJRWVQ/2KxDgWvV2F5oTkAS+5pnjKbl0n+A==", + "license": "MIT", + "peerDependencies": { + "axios": "^0.x || ^1.0.0", + "zod": "^3.x" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -10223,21 +10242,13 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, - "node_modules/axios-retry": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.9.1.tgz", - "integrity": "sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==", - "dependencies": { - "@babel/runtime": "^7.15.4", - "is-retry-allowed": "^2.2.0" - } - }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -11068,6 +11079,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", "engines": { "node": ">=4.5" } @@ -12294,11 +12306,12 @@ } }, "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", "dependencies": { - "node-fetch": "^2.6.12" + "node-fetch": "^2.7.0" } }, "node_modules/cross-spawn": { @@ -12352,6 +12365,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -13197,9 +13211,10 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" }, @@ -14329,6 +14344,27 @@ "node": ">=0.8.x" } }, + "node_modules/eventsource": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.5.tgz", + "integrity": "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", + "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -15046,6 +15082,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -16705,17 +16742,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-retry-allowed": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", - "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-root": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", @@ -18013,6 +18039,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/jito-ts/-/jito-ts-3.0.1.tgz", "integrity": "sha512-TSofF7KqcwyaWGjPaSYC8RDoNBY1TPRNBHdrw24bdIi7mQ5bFEDdYK3D//llw/ml8YDvcZlgd644WxhjLTS9yg==", + "license": "Apache-2.0", "dependencies": { "@grpc/grpc-js": "^1.8.13", "@noble/ed25519": "^1.7.1", @@ -18028,6 +18055,7 @@ "version": "1.77.4", "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.77.4.tgz", "integrity": "sha512-XdN0Lh4jdY7J8FYMyucxCwzn6Ga2Sr1DHDWRbqVzk7ZPmmpSPOVWHzO67X1cVT+jNi1D6gZi2tgjHgDPuj6e9Q==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "@noble/curves": "^1.0.0", @@ -18049,12 +18077,14 @@ "node_modules/jito-ts/node_modules/@solana/web3.js/node_modules/superstruct": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" + "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==", + "license": "MIT" }, "node_modules/jito-ts/node_modules/superstruct": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -18653,7 +18683,8 @@ "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -20822,7 +20853,8 @@ "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" }, "node_modules/parallel-transform": { "version": "1.2.0", @@ -22617,7 +22649,8 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "peer": true }, "node_modules/prr": { "version": "1.0.1", @@ -25311,6 +25344,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -26192,7 +26226,8 @@ "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==" + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", @@ -26866,7 +26901,8 @@ "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==" + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" }, "node_modules/tough-cookie": { "version": "4.1.4", @@ -26905,11 +26941,6 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, - "node_modules/ts-log": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", - "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==" - }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", @@ -29180,6 +29211,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/price_feeds/solana/send_usd/app/package.json b/price_feeds/solana/send_usd/app/package.json index 91b4a47..94c367c 100644 --- a/price_feeds/solana/send_usd/app/package.json +++ b/price_feeds/solana/send_usd/app/package.json @@ -1,10 +1,10 @@ { "name": "send_usd", - "version": "0.1.0", + "version": "0.2.0", "private": true, "dependencies": { - "@pythnetwork/price-service-client": "^1.8.2", - "@pythnetwork/pyth-solana-receiver": "^0.7.0", + "@pythnetwork/hermes-client": "^2.0.0", + "@pythnetwork/pyth-solana-receiver": "^0.10.0", "@solana/wallet-adapter-base": "^0.9.23", "@solana/wallet-adapter-react": "^0.15.35", "@solana/wallet-adapter-react-ui": "^0.9.35", @@ -49,4 +49,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/price_feeds/solana/send_usd/app/src/App.tsx b/price_feeds/solana/send_usd/app/src/App.tsx index 8c9235c..0cf62f7 100644 --- a/price_feeds/solana/send_usd/app/src/App.tsx +++ b/price_feeds/solana/send_usd/app/src/App.tsx @@ -20,7 +20,7 @@ import { Connection, PublicKey } from "@solana/web3.js"; import * as buffer from "buffer"; import { AnchorProvider, BN, Program, Wallet } from "@coral-xyz/anchor"; import { SendUSDApp, IDL } from "./idl/send_usd_app"; -import { PriceServiceConnection } from "@pythnetwork/price-service-client"; +import { HermesClient } from "@pythnetwork/hermes-client"; import { useState } from "react"; window.Buffer = buffer.Buffer; @@ -43,17 +43,13 @@ async function postPriceUpdate( if (!(wallet && destination && amount)) { return; } else { - const priceServiceConnection = new PriceServiceConnection(HERMES_URL, { - priceFeedRequestConfig: { binary: true }, - }); + const hermesClient = new HermesClient(HERMES_URL); const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet: wallet as Wallet, }); - const priceUpdateData = await priceServiceConnection.getLatestVaas([ - SOL_PRICE_FEED_ID, - ]); + const priceUpdateData = await hermesClient.getLatestPriceUpdates([SOL_PRICE_FEED_ID], { encoding: "base64" }); const sendUsdApp = new Program( IDL as SendUSDApp, @@ -64,7 +60,7 @@ async function postPriceUpdate( const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ closeUpdateAccounts: true, }); - await transactionBuilder.addPostPriceUpdates([priceUpdateData[0]]); + await transactionBuilder.addPostPriceUpdates(priceUpdateData.binary.data); await transactionBuilder.addPriceConsumerInstructions( async ( @@ -94,26 +90,115 @@ async function postPriceUpdate( } } -function Button(props: { +async function postTwapPriceUpdate( + connection: Connection, + wallet: AnchorWallet | undefined, + destination: PublicKey | undefined, + amount: number | undefined, + twapWindowSeconds: number +) { + if (!(wallet && destination && amount)) { + return; + } else { + const hermesClient = new HermesClient(HERMES_URL); + const pythSolanaReceiver = new PythSolanaReceiver({ + connection, + wallet: wallet as Wallet, + }); + + const twapUpdateData = await hermesClient.getLatestTwaps([SOL_PRICE_FEED_ID], twapWindowSeconds, { encoding: "base64" }); + + const sendUsdApp = new Program( + IDL as SendUSDApp, + SEND_USD_PROGRAM_ID, + new AnchorProvider(connection, wallet, AnchorProvider.defaultOptions()) + ); + + const transactionBuilder = pythSolanaReceiver.newTransactionBuilder({ + closeUpdateAccounts: true, + }); + await transactionBuilder.addPostTwapUpdates(twapUpdateData.binary.data); + + await transactionBuilder.addTwapConsumerInstructions( + async ( + getTwapUpdateAccount: (priceFeedId: string) => PublicKey + ): Promise => { + return [ + { + instruction: await sendUsdApp.methods + .sendUsingTwap(new BN(amount), new BN(twapWindowSeconds)) + .accounts({ + destination, + twapUpdate: getTwapUpdateAccount(SOL_PRICE_FEED_ID), + }) + .instruction(), + signers: [], + }, + ]; + } + ); + + await pythSolanaReceiver.provider.sendAll( + await transactionBuilder.buildVersionedTransactions({ + computeUnitPriceMicroLamports: 50000, + }), + { skipPreflight: true } + ); + } +} + +function Buttons(props: { destination: PublicKey | undefined; amount: number | undefined; }) { const connectionContext = useConnection(); const wallet = useAnchorWallet(); - + const [twapWindowSeconds, setTwapWindowSeconds] = useState(300); return ( - + <> +
+ +
+ +

TWAP Window (seconds): {twapWindowSeconds}

+ setTwapWindowSeconds(parseInt(e.target.value))} + style={{ width: "100%" }} + /> +
+
+ ); } @@ -146,24 +231,26 @@ function App() {

Click to send the amount of USD in SOL

-

- Destination (paste a Solana public key) -

- -

Amount (USD)

- - -