[price-pusher] sui (#825)
* sui pusher * cache mapping * typo * remove comment * add mainnet config * update readme * bump version
This commit is contained in:
parent
4a17e7f914
commit
1c529dd486
|
@ -9568,6 +9568,147 @@
|
|||
"resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz",
|
||||
"integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q=="
|
||||
},
|
||||
"node_modules/@mysten/bcs": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz",
|
||||
"integrity": "sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA==",
|
||||
"dependencies": {
|
||||
"bs58": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/bcs/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=="
|
||||
},
|
||||
"node_modules/@mysten/bcs/node_modules/bs58": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
|
||||
"integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
|
||||
"dependencies": {
|
||||
"base-x": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.34.0.tgz",
|
||||
"integrity": "sha512-mNb4vX+HSm/Y2oJSDeCNOUV7L7IXW1fRQ0zU7fFUAeJdNgf1ObFmxiItVCA7GU0EXoSPtYnpxcdJFiBcSnQtbA==",
|
||||
"dependencies": {
|
||||
"@mysten/bcs": "0.7.1",
|
||||
"@noble/curves": "^1.0.0",
|
||||
"@noble/hashes": "^1.3.0",
|
||||
"@scure/bip32": "^1.3.0",
|
||||
"@scure/bip39": "^1.2.0",
|
||||
"@suchipi/femver": "^1.0.0",
|
||||
"jayson": "^4.0.0",
|
||||
"rpc-websockets": "^7.5.1",
|
||||
"superstruct": "^1.0.3",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/@noble/hashes": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
|
||||
"integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/@scure/bip32": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz",
|
||||
"integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@noble/curves": "~1.0.0",
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/@scure/bip39": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
|
||||
"integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/@types/node": {
|
||||
"version": "12.20.55",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
|
||||
"integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/jayson": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz",
|
||||
"integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==",
|
||||
"dependencies": {
|
||||
"@types/connect": "^3.4.33",
|
||||
"@types/node": "^12.12.54",
|
||||
"@types/ws": "^7.4.4",
|
||||
"commander": "^2.20.3",
|
||||
"delay": "^5.0.0",
|
||||
"es6-promisify": "^5.0.0",
|
||||
"eyes": "^0.1.8",
|
||||
"isomorphic-ws": "^4.0.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"JSONStream": "^1.3.5",
|
||||
"uuid": "^8.3.2",
|
||||
"ws": "^7.4.5"
|
||||
},
|
||||
"bin": {
|
||||
"jayson": "bin/jayson.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/superstruct": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz",
|
||||
"integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mysten/sui.js/node_modules/ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.5.tgz",
|
||||
|
@ -15074,6 +15215,11 @@
|
|||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@suchipi/femver": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz",
|
||||
"integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg=="
|
||||
},
|
||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
|
@ -55432,6 +55578,7 @@
|
|||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@injectivelabs/sdk-ts": "1.10.72",
|
||||
"@mysten/sui.js": "^0.34.0",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
|
@ -64893,6 +65040,107 @@
|
|||
"resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz",
|
||||
"integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q=="
|
||||
},
|
||||
"@mysten/bcs": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz",
|
||||
"integrity": "sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA==",
|
||||
"requires": {
|
||||
"bs58": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"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=="
|
||||
},
|
||||
"bs58": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
|
||||
"integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
|
||||
"requires": {
|
||||
"base-x": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@mysten/sui.js": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.34.0.tgz",
|
||||
"integrity": "sha512-mNb4vX+HSm/Y2oJSDeCNOUV7L7IXW1fRQ0zU7fFUAeJdNgf1ObFmxiItVCA7GU0EXoSPtYnpxcdJFiBcSnQtbA==",
|
||||
"requires": {
|
||||
"@mysten/bcs": "0.7.1",
|
||||
"@noble/curves": "^1.0.0",
|
||||
"@noble/hashes": "^1.3.0",
|
||||
"@scure/bip32": "^1.3.0",
|
||||
"@scure/bip39": "^1.2.0",
|
||||
"@suchipi/femver": "^1.0.0",
|
||||
"jayson": "^4.0.0",
|
||||
"rpc-websockets": "^7.5.1",
|
||||
"superstruct": "^1.0.3",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/hashes": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
|
||||
"integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg=="
|
||||
},
|
||||
"@scure/bip32": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz",
|
||||
"integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==",
|
||||
"requires": {
|
||||
"@noble/curves": "~1.0.0",
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"@scure/bip39": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
|
||||
"integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
|
||||
"requires": {
|
||||
"@noble/hashes": "~1.3.0",
|
||||
"@scure/base": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.20.55",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
|
||||
"integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="
|
||||
},
|
||||
"jayson": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz",
|
||||
"integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==",
|
||||
"requires": {
|
||||
"@types/connect": "^3.4.33",
|
||||
"@types/node": "^12.12.54",
|
||||
"@types/ws": "^7.4.4",
|
||||
"commander": "^2.20.3",
|
||||
"delay": "^5.0.0",
|
||||
"es6-promisify": "^5.0.0",
|
||||
"eyes": "^0.1.8",
|
||||
"isomorphic-ws": "^4.0.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"JSONStream": "^1.3.5",
|
||||
"uuid": "^8.3.2",
|
||||
"ws": "^7.4.5"
|
||||
}
|
||||
},
|
||||
"superstruct": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz",
|
||||
"integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@next/env": {
|
||||
"version": "12.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.5.tgz",
|
||||
|
@ -67057,6 +67305,7 @@
|
|||
"version": "file:price_pusher",
|
||||
"requires": {
|
||||
"@injectivelabs/sdk-ts": "1.10.72",
|
||||
"@mysten/sui.js": "*",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
|
@ -72813,6 +73062,11 @@
|
|||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@suchipi/femver": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz",
|
||||
"integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg=="
|
||||
},
|
||||
"@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
|
|
|
@ -79,6 +79,29 @@ npm run start -- aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
|
|||
[--pushing-frequency 10] \
|
||||
[--polling-frequency 5] \
|
||||
|
||||
# For Sui
|
||||
npm run start -- sui
|
||||
--endpoint https://sui-testnet-rpc.allthatnode.com,
|
||||
--pyth-package-id 0x975e063f398f720af4f33ec06a927f14ea76ca24f7f8dd544aa62ab9d5d15f44,
|
||||
--pyth-state-id 0xd8afde3a48b4ff7212bd6829a150f43f59043221200d63504d981f62bff2e27a,
|
||||
--wormhole-package-id 0xcc029e2810f17f9f43f52262f40026a71fbdca40ed3803ad2884994361910b7e,
|
||||
--wormhole-state-id 0xebba4cc4d614f7a7cdbe883acc76d1cc767922bc96778e7b68be0d15fce27c02,
|
||||
--price-feed-to-price-info-object-table-id 0xf8929174008c662266a1adde78e1e8e33016eb7ad37d379481e860b911e40ed5,
|
||||
--price-service-endpoint https://xc-testnet.pyth.network,
|
||||
--mnemonic-file ./mnemonic,
|
||||
--price-config-file ./price-config.testnet.sample.yaml
|
||||
[--pushing-frequency 10] \
|
||||
[--polling-frequency 5] \
|
||||
|
||||
|
||||
|
||||
--endpoint https://fullnode.testnet.aptoslabs.com/v1 \
|
||||
--pyth-contract-address 0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387 --price-service-endpoint "https://xc-testnet.pyth.network" \
|
||||
--price-config-file "./price-config.testnet.sample.yaml" \
|
||||
--mnemonic-file "path/to/mnemonic.txt" \
|
||||
[--pushing-frequency 10] \
|
||||
[--polling-frequency 5] \
|
||||
|
||||
|
||||
# Or, run the price pusher docker image instead of building from the source
|
||||
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"endpoint": "https://sui-testnet-rpc.allthatnode.com",
|
||||
"pyth-package-id": "0x00b53b0f4174108627fbee72e2498b58d6a2714cded53fac537034c220d26302",
|
||||
"pyth-state-id": "0xf9ff3ef935ef6cdfb659a203bf2754cebeb63346e29114a535ea6f41315e5a3f",
|
||||
"wormhole-package-id": "0x5306f64e312b581766351c07af79c72fcb1cd25147157fdc2f8ad76de9a3fb6a",
|
||||
"wormhole-state-id": "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
|
||||
"price-feed-to-price-info-object-table-id": "0x14b4697477d24c30c8eecc31dd1bd49a3115a9fe0db6bd4fd570cf14640b79a0",
|
||||
"price-service-endpoint": "https://xc-mainnet.pyth.network",
|
||||
"mnemonic-file": "./mnemonic",
|
||||
"price-config-file": "./price-config.mainnet.sample.yaml"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"endpoint": "https://sui-testnet-rpc.allthatnode.com",
|
||||
"pyth-package-id": "0x975e063f398f720af4f33ec06a927f14ea76ca24f7f8dd544aa62ab9d5d15f44",
|
||||
"pyth-state-id": "0xd8afde3a48b4ff7212bd6829a150f43f59043221200d63504d981f62bff2e27a",
|
||||
"wormhole-package-id": "0xcc029e2810f17f9f43f52262f40026a71fbdca40ed3803ad2884994361910b7e",
|
||||
"wormhole-state-id": "0xebba4cc4d614f7a7cdbe883acc76d1cc767922bc96778e7b68be0d15fce27c02",
|
||||
"price-feed-to-price-info-object-table-id": "0xf8929174008c662266a1adde78e1e8e33016eb7ad37d379481e860b911e40ed5",
|
||||
"price-service-endpoint": "https://xc-testnet.pyth.network",
|
||||
"mnemonic-file": "./mnemonic",
|
||||
"price-config-file": "./price-config.testnet.sample.yaml"
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@pythnetwork/price-pusher",
|
||||
"version": "5.1.0",
|
||||
"version": "5.2.0",
|
||||
"description": "Pyth Price Pusher",
|
||||
"homepage": "https://pyth.network",
|
||||
"main": "lib/index.js",
|
||||
|
@ -52,6 +52,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@injectivelabs/sdk-ts": "1.10.72",
|
||||
"@mysten/sui.js": "^0.34.0",
|
||||
"@pythnetwork/price-service-client": "*",
|
||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||
"@truffle/hdwallet-provider": "^2.1.3",
|
||||
|
|
|
@ -4,6 +4,7 @@ import { hideBin } from "yargs/helpers";
|
|||
import injective from "./injective/command";
|
||||
import evm from "./evm/command";
|
||||
import aptos from "./aptos/command";
|
||||
import sui from "./sui/command";
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.config("config")
|
||||
|
@ -11,4 +12,5 @@ yargs(hideBin(process.argv))
|
|||
.command(evm)
|
||||
.command(injective)
|
||||
.command(aptos)
|
||||
.command(sui)
|
||||
.help().argv;
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import * as options from "../options";
|
||||
import { readPriceConfigFile } from "../price-config";
|
||||
import fs from "fs";
|
||||
import { PythPriceListener } from "../pyth-price-listener";
|
||||
import { Controller } from "../controller";
|
||||
import { Options } from "yargs";
|
||||
import { SuiPriceListener, SuiPricePusher } from "./sui";
|
||||
|
||||
export default {
|
||||
command: "sui",
|
||||
describe:
|
||||
"Run price pusher for sui. Most of the arguments below are" +
|
||||
"network specific, so there's one set of values for mainnet and" +
|
||||
"another for testnet. See config.sui..sample.json for the " +
|
||||
"appropriate values for your network. ",
|
||||
builder: {
|
||||
endpoint: {
|
||||
description:
|
||||
"RPC endpoint URL for sui. The pusher will periodically" +
|
||||
"poll for updates. The polling interval is configurable via the " +
|
||||
"`polling-frequency` command-line argument.",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
"pyth-package-id": {
|
||||
description:
|
||||
"Pyth Package Id. Can be found here" +
|
||||
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
"pyth-state-id": {
|
||||
description:
|
||||
"Pyth State Id. Can be found here" +
|
||||
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
"wormhole-package-id": {
|
||||
description:
|
||||
"Wormhole Package Id. Can be found here" +
|
||||
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
"wormhole-state-id": {
|
||||
description:
|
||||
"Wormhole State Id. Can be found here" +
|
||||
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
"price-feed-to-price-info-object-table-id": {
|
||||
description:
|
||||
"This is the id of the table which stored the information related to price data. You can find it here: " +
|
||||
"https://docs.pyth.network/pythnet-price-feeds/sui",
|
||||
type: "string",
|
||||
required: true,
|
||||
} as Options,
|
||||
...options.priceConfigFile,
|
||||
...options.priceServiceEndpoint,
|
||||
...options.mnemonicFile,
|
||||
...options.pollingFrequency,
|
||||
...options.pushingFrequency,
|
||||
},
|
||||
handler: function (argv: any) {
|
||||
const {
|
||||
endpoint,
|
||||
priceConfigFile,
|
||||
priceServiceEndpoint,
|
||||
mnemonicFile,
|
||||
pushingFrequency,
|
||||
pollingFrequency,
|
||||
pythPackageId,
|
||||
pythStateId,
|
||||
wormholePackageId,
|
||||
wormholeStateId,
|
||||
priceFeedToPriceInfoObjectTableId,
|
||||
} = argv;
|
||||
|
||||
const priceConfigs = readPriceConfigFile(priceConfigFile);
|
||||
const priceServiceConnection = new PriceServiceConnection(
|
||||
priceServiceEndpoint,
|
||||
{
|
||||
logger: {
|
||||
// Log only warnings and errors from the price service client
|
||||
info: () => undefined,
|
||||
warn: console.warn,
|
||||
error: console.error,
|
||||
debug: () => undefined,
|
||||
trace: () => undefined,
|
||||
},
|
||||
}
|
||||
);
|
||||
const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
|
||||
|
||||
const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
|
||||
|
||||
const pythListener = new PythPriceListener(
|
||||
priceServiceConnection,
|
||||
priceItems
|
||||
);
|
||||
|
||||
const suiListener = new SuiPriceListener(
|
||||
pythPackageId,
|
||||
priceFeedToPriceInfoObjectTableId,
|
||||
endpoint,
|
||||
priceItems,
|
||||
{ pollingFrequency }
|
||||
);
|
||||
const suiPusher = new SuiPricePusher(
|
||||
priceServiceConnection,
|
||||
pythPackageId,
|
||||
pythStateId,
|
||||
wormholePackageId,
|
||||
wormholeStateId,
|
||||
priceFeedToPriceInfoObjectTableId,
|
||||
endpoint,
|
||||
mnemonic
|
||||
);
|
||||
|
||||
const controller = new Controller(
|
||||
priceConfigs,
|
||||
pythListener,
|
||||
suiListener,
|
||||
suiPusher,
|
||||
{ pushingFrequency }
|
||||
);
|
||||
|
||||
controller.start();
|
||||
},
|
||||
};
|
|
@ -0,0 +1,254 @@
|
|||
import {
|
||||
ChainPriceListener,
|
||||
IPricePusher,
|
||||
PriceInfo,
|
||||
PriceItem,
|
||||
} from "../interface";
|
||||
import { DurationInSeconds } from "../utils";
|
||||
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||
import {
|
||||
JsonRpcProvider,
|
||||
Connection,
|
||||
Ed25519Keypair,
|
||||
RawSigner,
|
||||
TransactionBlock,
|
||||
SUI_CLOCK_OBJECT_ID,
|
||||
} from "@mysten/sui.js";
|
||||
|
||||
export class SuiPriceListener extends ChainPriceListener {
|
||||
constructor(
|
||||
private pythPackageId: string,
|
||||
private priceFeedToPriceInfoObjectTableId: string,
|
||||
private endpoint: string,
|
||||
priceItems: PriceItem[],
|
||||
config: {
|
||||
pollingFrequency: DurationInSeconds;
|
||||
}
|
||||
) {
|
||||
super("sui", config.pollingFrequency, priceItems);
|
||||
}
|
||||
|
||||
async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
|
||||
try {
|
||||
const provider = new JsonRpcProvider(
|
||||
new Connection({ fullnode: this.endpoint })
|
||||
);
|
||||
|
||||
const priceInfoObjectId = await priceIdToPriceInfoObjectId(
|
||||
provider,
|
||||
this.pythPackageId,
|
||||
this.priceFeedToPriceInfoObjectTableId,
|
||||
priceId
|
||||
);
|
||||
|
||||
// Fetching the price info object for the above priceInfoObjectId
|
||||
const priceInfoObject = await provider.getObject({
|
||||
id: priceInfoObjectId,
|
||||
options: { showContent: true },
|
||||
});
|
||||
|
||||
if (
|
||||
priceInfoObject.data === undefined ||
|
||||
priceInfoObject.data.content === undefined
|
||||
)
|
||||
throw new Error("Price not found on chain for price id " + priceId);
|
||||
|
||||
if (priceInfoObject.data.content.dataType !== "moveObject")
|
||||
throw new Error("fetched object datatype should be moveObject");
|
||||
|
||||
const { magnitude, negative } =
|
||||
priceInfoObject.data.content.fields.price_info.fields.price_feed.fields
|
||||
.price.fields.price.fields;
|
||||
|
||||
const conf =
|
||||
priceInfoObject.data.content.fields.price_info.fields.price_feed.fields
|
||||
.price.fields.conf;
|
||||
|
||||
const timestamp =
|
||||
priceInfoObject.data.content.fields.price_info.fields.price_feed.fields
|
||||
.price.fields.timestamp;
|
||||
|
||||
return {
|
||||
price: negative ? "-" + magnitude : magnitude,
|
||||
conf,
|
||||
publishTime: Number(timestamp),
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(`Polling Sui on-chain price for ${priceId} failed. Error:`);
|
||||
console.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SuiPricePusher implements IPricePusher {
|
||||
private readonly signer: RawSigner;
|
||||
constructor(
|
||||
private priceServiceConnection: PriceServiceConnection,
|
||||
private pythPackageId: string,
|
||||
private pythStateId: string,
|
||||
private wormholePackageId: string,
|
||||
private wormholeStateId: string,
|
||||
private priceFeedToPriceInfoObjectTableId: string,
|
||||
endpoint: string,
|
||||
mnemonic: string
|
||||
) {
|
||||
this.signer = new RawSigner(
|
||||
Ed25519Keypair.deriveKeypair(mnemonic),
|
||||
new JsonRpcProvider(new Connection({ fullnode: endpoint }))
|
||||
);
|
||||
}
|
||||
|
||||
async updatePriceFeed(
|
||||
priceIds: string[],
|
||||
pubTimesToPush: number[]
|
||||
): Promise<void> {
|
||||
if (priceIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (priceIds.length !== pubTimesToPush.length)
|
||||
throw new Error("Invalid arguments");
|
||||
|
||||
const tx = new TransactionBlock();
|
||||
|
||||
const vaas = await this.priceServiceConnection.getLatestVaas(priceIds);
|
||||
|
||||
// Parse our batch price attestation VAA bytes using Wormhole.
|
||||
// Check out the Wormhole cross-chain bridge and generic messaging protocol here:
|
||||
// https://github.com/wormhole-foundation/wormhole
|
||||
let verified_vaas: any = [];
|
||||
for (const vaa of vaas) {
|
||||
const [verified_vaa] = tx.moveCall({
|
||||
target: `${this.wormholePackageId}::vaa::parse_and_verify`,
|
||||
arguments: [
|
||||
tx.object(this.wormholeStateId),
|
||||
tx.pure([...Buffer.from(vaa, "base64")]),
|
||||
tx.object(SUI_CLOCK_OBJECT_ID),
|
||||
],
|
||||
});
|
||||
verified_vaas = verified_vaas.concat(verified_vaa);
|
||||
}
|
||||
|
||||
// Create a hot potato vector of price feed updates that will
|
||||
// be used to update price feeds.
|
||||
let [price_updates_hot_potato] = tx.moveCall({
|
||||
target: `${this.pythPackageId}::pyth::create_price_infos_hot_potato`,
|
||||
arguments: [
|
||||
tx.object(this.pythStateId),
|
||||
tx.makeMoveVec({
|
||||
type: `${this.wormholePackageId}::vaa::VAA`,
|
||||
objects: verified_vaas,
|
||||
}),
|
||||
tx.object(SUI_CLOCK_OBJECT_ID),
|
||||
],
|
||||
});
|
||||
|
||||
// Update each price info object (containing our price feeds of interest)
|
||||
// using the hot potato vector.
|
||||
for (const priceId of priceIds) {
|
||||
let priceInfoObjectId;
|
||||
try {
|
||||
priceInfoObjectId = await priceIdToPriceInfoObjectId(
|
||||
this.signer.provider,
|
||||
this.pythPackageId,
|
||||
this.priceFeedToPriceInfoObjectTableId,
|
||||
priceId
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Error fetching price info object id for ", priceId);
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
const coin = tx.splitCoins(tx.gas, [tx.pure(1)]);
|
||||
[price_updates_hot_potato] = tx.moveCall({
|
||||
target: `${this.pythPackageId}::pyth::update_single_price_feed`,
|
||||
arguments: [
|
||||
tx.object(this.pythStateId),
|
||||
price_updates_hot_potato,
|
||||
tx.object(priceInfoObjectId),
|
||||
coin,
|
||||
tx.object(SUI_CLOCK_OBJECT_ID),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// Explicitly destroy the hot potato vector, since it can't be dropped
|
||||
// automatically.
|
||||
tx.moveCall({
|
||||
target: `${this.pythPackageId}::hot_potato_vector::destroy`,
|
||||
arguments: [price_updates_hot_potato],
|
||||
typeArguments: [`${this.pythPackageId}::price_info::PriceInfo`],
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await this.signer.signAndExecuteTransactionBlock({
|
||||
transactionBlock: tx,
|
||||
options: {
|
||||
showInput: true,
|
||||
showEffects: true,
|
||||
showEvents: true,
|
||||
showObjectChanges: true,
|
||||
showBalanceChanges: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
"Successfully updated price with transaction digest ",
|
||||
result.digest
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("Error when signAndExecuteTransactionBlock");
|
||||
if (String(e).includes("GasBalanceTooLow")) {
|
||||
console.log("Insufficient Gas Amount. Please top up your account");
|
||||
process.exit();
|
||||
}
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are calculating stored price info object id for given price id
|
||||
// The mapping between which is static. Hence, we are caching it here.
|
||||
const CACHE: { [priceId: string]: string } = {};
|
||||
|
||||
// For given priceid, this method will fetch the price info object id
|
||||
// where the price information for the corresponding price feed is stored
|
||||
async function priceIdToPriceInfoObjectId(
|
||||
provider: JsonRpcProvider,
|
||||
pythPackageId: string,
|
||||
priceFeedToPriceInfoObjectTableId: string,
|
||||
priceId: string
|
||||
) {
|
||||
// Check if this was fetched before.
|
||||
if (CACHE[priceId] !== undefined) return CACHE[priceId];
|
||||
|
||||
const storedObjectID = await provider.getDynamicFieldObject({
|
||||
parentId: priceFeedToPriceInfoObjectTableId,
|
||||
name: {
|
||||
type: `${pythPackageId}::price_identifier::PriceIdentifier`,
|
||||
value: {
|
||||
bytes: "0x" + priceId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (storedObjectID.error !== undefined) throw storedObjectID.error;
|
||||
|
||||
if (
|
||||
storedObjectID.data === undefined ||
|
||||
storedObjectID.data.content === undefined
|
||||
)
|
||||
throw new Error("Price not found on chain for price id " + priceId);
|
||||
|
||||
if (storedObjectID.data.content.dataType !== "moveObject")
|
||||
throw new Error("fetched object datatype should be moveObject");
|
||||
// This ID points to the price info object for the given price id stored on chain
|
||||
const priceInfoObjectId = storedObjectID.data.content.fields.value;
|
||||
|
||||
// cache the price info object id
|
||||
CACHE[priceId] = priceInfoObjectId;
|
||||
|
||||
return priceInfoObjectId;
|
||||
}
|
Loading…
Reference in New Issue