[price-pusher] support for aptos (#815)
* aptos price listener * price pusher aptos * add comment * update package lock * remove eslint disable comments * bump version * npm i at root * update readme * address feedback * update readme * json fix
This commit is contained in:
parent
1dbc592836
commit
3fc996d6f9
|
@ -11514,6 +11514,10 @@
|
||||||
"resolved": "target_chains/cosmwasm/tools",
|
"resolved": "target_chains/cosmwasm/tools",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@pythnetwork/eth-oracle-swap-example-frontend": {
|
||||||
|
"resolved": "target_chains/ethereum/examples/oracle_swap/app",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@pythnetwork/price-pusher": {
|
"node_modules/@pythnetwork/price-pusher": {
|
||||||
"resolved": "price_pusher",
|
"resolved": "price_pusher",
|
||||||
"link": true
|
"link": true
|
||||||
|
@ -21067,9 +21071,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/aptos": {
|
"node_modules/aptos": {
|
||||||
"version": "1.6.0",
|
"version": "1.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.8.5.tgz",
|
||||||
"integrity": "sha512-5khjDwrDeNMDBFRcZAmETW20D+V2AqTdsgqkh6bvvl70BtRXdkitN0saM05gf1rK3atnO9PyUKO8iRaBDG5qtA==",
|
"integrity": "sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "1.1.3",
|
"@noble/hashes": "1.1.3",
|
||||||
"@scure/bip39": "1.1.0",
|
"@scure/bip39": "1.1.0",
|
||||||
|
@ -50989,10 +50993,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"node_modules/@pythnetwork/eth-oracle-swap-example-frontend": {
|
|
||||||
"resolved": "target_chains/ethereum/examples/oracle_swap/app",
|
|
||||||
"link": true
|
|
||||||
},
|
|
||||||
"node_modules/traverse-chain": {
|
"node_modules/traverse-chain": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
||||||
|
@ -55110,13 +55110,14 @@
|
||||||
},
|
},
|
||||||
"price_pusher": {
|
"price_pusher": {
|
||||||
"name": "@pythnetwork/price-pusher",
|
"name": "@pythnetwork/price-pusher",
|
||||||
"version": "5.0.0",
|
"version": "5.1.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@injectivelabs/sdk-ts": "1.10.72",
|
"@injectivelabs/sdk-ts": "1.10.72",
|
||||||
"@pythnetwork/price-service-client": "*",
|
"@pythnetwork/price-service-client": "*",
|
||||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||||
"@truffle/hdwallet-provider": "^2.1.3",
|
"@truffle/hdwallet-provider": "^2.1.3",
|
||||||
|
"aptos": "^1.8.5",
|
||||||
"joi": "^17.6.0",
|
"joi": "^17.6.0",
|
||||||
"web3": "^1.8.1",
|
"web3": "^1.8.1",
|
||||||
"web3-eth-contract": "^1.8.1",
|
"web3-eth-contract": "^1.8.1",
|
||||||
|
@ -57475,6 +57476,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"target_chains/ethereum/examples/oracle_swap/app": {
|
"target_chains/ethereum/examples/oracle_swap/app": {
|
||||||
|
"name": "@pythnetwork/eth-oracle-swap-example-frontend",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pythnetwork/pyth-evm-js": "*",
|
"@pythnetwork/pyth-evm-js": "*",
|
||||||
|
@ -66433,6 +66435,107 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@pythnetwork/eth-oracle-swap-example-frontend": {
|
||||||
|
"version": "file:target_chains/ethereum/examples/oracle_swap/app",
|
||||||
|
"requires": {
|
||||||
|
"@pythnetwork/pyth-evm-js": "*",
|
||||||
|
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||||
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
|
"@testing-library/react": "^13.4.0",
|
||||||
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"@types/jest": "^27.5.2",
|
||||||
|
"@types/node": "^16.11.64",
|
||||||
|
"@types/react": "^18.0.21",
|
||||||
|
"@types/react-dom": "^18.0.6",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
|
"ethers": "^5.7.2",
|
||||||
|
"metamask-react": "^2.4.0",
|
||||||
|
"prettier": "^2.7.1",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-scripts": "5.0.1",
|
||||||
|
"typescript": "^4.8.4",
|
||||||
|
"web-vitals": "^2.1.4",
|
||||||
|
"web3": "^1.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/jest": {
|
||||||
|
"version": "27.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
|
||||||
|
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
|
||||||
|
"requires": {
|
||||||
|
"jest-matcher-utils": "^27.0.0",
|
||||||
|
"pretty-format": "^27.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"version": "16.18.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.28.tgz",
|
||||||
|
"integrity": "sha512-SNMfiPqsiPoYfmyi+2qnDO4nZyMIOCab/CW+Slcml0lhIzkOizYzWtt/A7tgB3TSitd+YJKi8fSC2Cpm/VCp7A=="
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
||||||
|
},
|
||||||
|
"buffer": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
|
"requires": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"diff-sequences": {
|
||||||
|
"version": "27.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
|
||||||
|
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
|
||||||
|
},
|
||||||
|
"jest-diff": {
|
||||||
|
"version": "27.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
|
||||||
|
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^4.0.0",
|
||||||
|
"diff-sequences": "^27.5.1",
|
||||||
|
"jest-get-type": "^27.5.1",
|
||||||
|
"pretty-format": "^27.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jest-get-type": {
|
||||||
|
"version": "27.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
|
||||||
|
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
|
||||||
|
},
|
||||||
|
"jest-matcher-utils": {
|
||||||
|
"version": "27.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
|
||||||
|
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^4.0.0",
|
||||||
|
"jest-diff": "^27.5.1",
|
||||||
|
"jest-get-type": "^27.5.1",
|
||||||
|
"pretty-format": "^27.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pretty-format": {
|
||||||
|
"version": "27.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||||
|
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.1",
|
||||||
|
"ansi-styles": "^5.0.0",
|
||||||
|
"react-is": "^17.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-is": {
|
||||||
|
"version": "17.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@pythnetwork/price-pusher": {
|
"@pythnetwork/price-pusher": {
|
||||||
"version": "file:price_pusher",
|
"version": "file:price_pusher",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -66445,6 +66548,7 @@
|
||||||
"@types/yargs": "^17.0.10",
|
"@types/yargs": "^17.0.10",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||||
"@typescript-eslint/parser": "^5.20.0",
|
"@typescript-eslint/parser": "^5.20.0",
|
||||||
|
"aptos": "^1.8.5",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"joi": "^17.6.0",
|
"joi": "^17.6.0",
|
||||||
|
@ -77292,9 +77396,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"aptos": {
|
"aptos": {
|
||||||
"version": "1.6.0",
|
"version": "1.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/aptos/-/aptos-1.8.5.tgz",
|
||||||
"integrity": "sha512-5khjDwrDeNMDBFRcZAmETW20D+V2AqTdsgqkh6bvvl70BtRXdkitN0saM05gf1rK3atnO9PyUKO8iRaBDG5qtA==",
|
"integrity": "sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@noble/hashes": "1.1.3",
|
"@noble/hashes": "1.1.3",
|
||||||
"@scure/bip39": "1.1.0",
|
"@scure/bip39": "1.1.0",
|
||||||
|
@ -101582,107 +101686,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"@pythnetwork/eth-oracle-swap-example-frontend": {
|
|
||||||
"version": "file:target_chains/ethereum/examples/oracle_swap/app",
|
|
||||||
"requires": {
|
|
||||||
"@pythnetwork/pyth-evm-js": "*",
|
|
||||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
|
||||||
"@testing-library/react": "^13.4.0",
|
|
||||||
"@testing-library/user-event": "^13.5.0",
|
|
||||||
"@types/jest": "^27.5.2",
|
|
||||||
"@types/node": "^16.11.64",
|
|
||||||
"@types/react": "^18.0.21",
|
|
||||||
"@types/react-dom": "^18.0.6",
|
|
||||||
"buffer": "^6.0.3",
|
|
||||||
"ethers": "^5.7.2",
|
|
||||||
"metamask-react": "^2.4.0",
|
|
||||||
"prettier": "^2.7.1",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-scripts": "5.0.1",
|
|
||||||
"typescript": "^4.8.4",
|
|
||||||
"web-vitals": "^2.1.4",
|
|
||||||
"web3": "^1.8.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@types/jest": {
|
|
||||||
"version": "27.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz",
|
|
||||||
"integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==",
|
|
||||||
"requires": {
|
|
||||||
"jest-matcher-utils": "^27.0.0",
|
|
||||||
"pretty-format": "^27.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/node": {
|
|
||||||
"version": "16.18.28",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.28.tgz",
|
|
||||||
"integrity": "sha512-SNMfiPqsiPoYfmyi+2qnDO4nZyMIOCab/CW+Slcml0lhIzkOizYzWtt/A7tgB3TSitd+YJKi8fSC2Cpm/VCp7A=="
|
|
||||||
},
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "5.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
|
||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
|
||||||
},
|
|
||||||
"buffer": {
|
|
||||||
"version": "6.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
|
||||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
|
||||||
"requires": {
|
|
||||||
"base64-js": "^1.3.1",
|
|
||||||
"ieee754": "^1.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"diff-sequences": {
|
|
||||||
"version": "27.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
|
|
||||||
"integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ=="
|
|
||||||
},
|
|
||||||
"jest-diff": {
|
|
||||||
"version": "27.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz",
|
|
||||||
"integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==",
|
|
||||||
"requires": {
|
|
||||||
"chalk": "^4.0.0",
|
|
||||||
"diff-sequences": "^27.5.1",
|
|
||||||
"jest-get-type": "^27.5.1",
|
|
||||||
"pretty-format": "^27.5.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jest-get-type": {
|
|
||||||
"version": "27.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz",
|
|
||||||
"integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw=="
|
|
||||||
},
|
|
||||||
"jest-matcher-utils": {
|
|
||||||
"version": "27.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz",
|
|
||||||
"integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==",
|
|
||||||
"requires": {
|
|
||||||
"chalk": "^4.0.0",
|
|
||||||
"jest-diff": "^27.5.1",
|
|
||||||
"jest-get-type": "^27.5.1",
|
|
||||||
"pretty-format": "^27.5.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pretty-format": {
|
|
||||||
"version": "27.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
|
||||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^5.0.1",
|
|
||||||
"ansi-styles": "^5.0.0",
|
|
||||||
"react-is": "^17.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-is": {
|
|
||||||
"version": "17.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"traverse-chain": {
|
"traverse-chain": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
||||||
|
|
|
@ -71,6 +71,14 @@ npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
|
||||||
[--pushing-frequency 10] \
|
[--pushing-frequency 10] \
|
||||||
[--polling-frequency 5] \
|
[--polling-frequency 5] \
|
||||||
|
|
||||||
|
# For Aptos
|
||||||
|
npm run start -- aptos --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
|
# 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>
|
docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-arguments>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"endpoint": "https://fullnode.testnet.aptoslabs.com/v1",
|
||||||
|
"pyth-contract-address": "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387",
|
||||||
|
"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",
|
"name": "@pythnetwork/price-pusher",
|
||||||
"version": "5.0.0",
|
"version": "5.1.0",
|
||||||
"description": "Pyth Price Pusher",
|
"description": "Pyth Price Pusher",
|
||||||
"homepage": "https://pyth.network",
|
"homepage": "https://pyth.network",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
"@pythnetwork/price-service-client": "*",
|
"@pythnetwork/price-service-client": "*",
|
||||||
"@pythnetwork/pyth-sdk-solidity": "*",
|
"@pythnetwork/pyth-sdk-solidity": "*",
|
||||||
"@truffle/hdwallet-provider": "^2.1.3",
|
"@truffle/hdwallet-provider": "^2.1.3",
|
||||||
|
"aptos": "^1.8.5",
|
||||||
"joi": "^17.6.0",
|
"joi": "^17.6.0",
|
||||||
"web3": "^1.8.1",
|
"web3": "^1.8.1",
|
||||||
"web3-eth-contract": "^1.8.1",
|
"web3-eth-contract": "^1.8.1",
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
import {
|
||||||
|
ChainPriceListener,
|
||||||
|
IPricePusher,
|
||||||
|
PriceInfo,
|
||||||
|
PriceItem,
|
||||||
|
} from "../interface";
|
||||||
|
import { AptosAccount, AptosClient, TxnBuilderTypes } from "aptos";
|
||||||
|
import { DurationInSeconds } from "../utils";
|
||||||
|
import { PriceServiceConnection } from "@pythnetwork/price-service-client";
|
||||||
|
import { PushAttempt } from "../common";
|
||||||
|
|
||||||
|
export class AptosPriceListener extends ChainPriceListener {
|
||||||
|
constructor(
|
||||||
|
private pythModule: string,
|
||||||
|
private endpoint: string,
|
||||||
|
priceItems: PriceItem[],
|
||||||
|
config: {
|
||||||
|
pollingFrequency: DurationInSeconds;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
super("aptos", config.pollingFrequency, priceItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
|
||||||
|
try {
|
||||||
|
const client = new AptosClient(this.endpoint);
|
||||||
|
|
||||||
|
const res = await client.getAccountResource(
|
||||||
|
this.pythModule,
|
||||||
|
`${this.pythModule}::state::LatestPriceInfo`
|
||||||
|
);
|
||||||
|
|
||||||
|
// This depends upon the pyth contract storage on Aptos and should not be undefined.
|
||||||
|
// If undefined, there has been some change and we would need to update accordingly.
|
||||||
|
const handle = (res.data as any).info.handle;
|
||||||
|
|
||||||
|
const priceItemRes = await client.getTableItem(handle, {
|
||||||
|
key_type: `${this.pythModule}::price_identifier::PriceIdentifier`,
|
||||||
|
value_type: `${this.pythModule}::price_info::PriceInfo`,
|
||||||
|
key: {
|
||||||
|
bytes: priceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const multiplier =
|
||||||
|
priceItemRes.price_feed.price.price.negative === true ? -1 : 1;
|
||||||
|
const price =
|
||||||
|
multiplier * Number(priceItemRes.price_feed.price.price.magnitude);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Polled an Aptos on-chain price for feed ${this.priceIdToAlias.get(
|
||||||
|
priceId
|
||||||
|
)} (${priceId}).`
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
price: price.toString(),
|
||||||
|
conf: priceItemRes.price_feed.price.conf,
|
||||||
|
publishTime: Number(priceItemRes.price_feed.price.timestamp),
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
`Polling Aptos on-chain price for ${priceId} failed. Error:`
|
||||||
|
);
|
||||||
|
console.error(e);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AptosPricePusher implements IPricePusher {
|
||||||
|
private lastPushAttempt: PushAttempt | undefined;
|
||||||
|
|
||||||
|
private readonly accountHDPath = "m/44'/637'/0'/0'/0'";
|
||||||
|
constructor(
|
||||||
|
private priceServiceConnection: PriceServiceConnection,
|
||||||
|
private pythContractAddress: string,
|
||||||
|
private endpoint: string,
|
||||||
|
private mnemonic: string,
|
||||||
|
private overrideGasPriceMultiplier: number
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets price update data which then can be submitted to the Pyth contract to update the prices.
|
||||||
|
* This will throw an axios error if there is a network problem or the price service returns a non-ok response (e.g: Invalid price ids)
|
||||||
|
*
|
||||||
|
* @param priceIds Array of hex-encoded price ids.
|
||||||
|
* @returns Array of price update data.
|
||||||
|
*/
|
||||||
|
async getPriceFeedsUpdateData(priceIds: string[]): Promise<number[][]> {
|
||||||
|
// Fetch the latest price feed update VAAs from the price service
|
||||||
|
const latestVaas = await this.priceServiceConnection.getLatestVaas(
|
||||||
|
priceIds
|
||||||
|
);
|
||||||
|
return latestVaas.map((vaa) => Array.from(Buffer.from(vaa, "base64")));
|
||||||
|
}
|
||||||
|
|
||||||
|
async updatePriceFeed(
|
||||||
|
priceIds: string[],
|
||||||
|
pubTimesToPush: number[]
|
||||||
|
): Promise<void> {
|
||||||
|
if (priceIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priceIds.length !== pubTimesToPush.length)
|
||||||
|
throw new Error("Invalid arguments");
|
||||||
|
|
||||||
|
let priceFeedUpdateData;
|
||||||
|
try {
|
||||||
|
// get the latest VAAs for updatePriceFeed and then push them
|
||||||
|
priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error fetching the latest vaas to push");
|
||||||
|
console.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const account = AptosAccount.fromDerivePath(
|
||||||
|
this.accountHDPath,
|
||||||
|
this.mnemonic
|
||||||
|
);
|
||||||
|
const client = new AptosClient(this.endpoint);
|
||||||
|
|
||||||
|
const rawTx = await client.generateTransaction(account.address(), {
|
||||||
|
function: `${this.pythContractAddress}::pyth::update_price_feeds_if_fresh_with_funder`,
|
||||||
|
type_arguments: [],
|
||||||
|
arguments: [
|
||||||
|
priceFeedUpdateData,
|
||||||
|
priceIds.map((priceId) => Buffer.from(priceId, "hex")),
|
||||||
|
pubTimesToPush,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const simulation = await client.simulateTransaction(account, rawTx, {
|
||||||
|
estimateGasUnitPrice: true,
|
||||||
|
estimateMaxGasAmount: true,
|
||||||
|
estimatePrioritizedGasUnitPrice: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Transactions on Aptos can be prioritized by paying a higher gas unit price.
|
||||||
|
// We are storing the gas unit price paid for the last transaction.
|
||||||
|
// If that transaction is not added to the block, we are increasing the gas unit price
|
||||||
|
// by multiplying the old gas unit price with `this.overrideGasPriceMultiplier`.
|
||||||
|
// After which we are sending a transaction with the same sequence number as the last
|
||||||
|
// transaction. Since they have the same sequence number only one of them will be added to
|
||||||
|
// the block and we won't be paying fees twice.
|
||||||
|
let gasUnitPrice = Number(simulation[0].gas_unit_price);
|
||||||
|
if (
|
||||||
|
this.lastPushAttempt !== undefined &&
|
||||||
|
Number(simulation[0].sequence_number) === this.lastPushAttempt.nonce
|
||||||
|
) {
|
||||||
|
const newGasUnitPrice = Number(
|
||||||
|
this.lastPushAttempt.gasPrice * this.overrideGasPriceMultiplier
|
||||||
|
);
|
||||||
|
if (gasUnitPrice < newGasUnitPrice) gasUnitPrice = newGasUnitPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gasUsed = Number(simulation[0].gas_used) * 1.5;
|
||||||
|
const maxGasAmount = Number(gasUnitPrice * gasUsed);
|
||||||
|
|
||||||
|
const rawTxWithFee = new TxnBuilderTypes.RawTransaction(
|
||||||
|
rawTx.sender,
|
||||||
|
rawTx.sequence_number,
|
||||||
|
rawTx.payload,
|
||||||
|
BigInt(maxGasAmount.toFixed()),
|
||||||
|
BigInt(gasUnitPrice.toFixed()),
|
||||||
|
rawTx.expiration_timestamp_secs,
|
||||||
|
rawTx.chain_id
|
||||||
|
);
|
||||||
|
|
||||||
|
const signedTx = await client.signTransaction(account, rawTxWithFee);
|
||||||
|
const pendingTx = await client.submitTransaction(signedTx);
|
||||||
|
|
||||||
|
console.log("Succesfully broadcasted txHash:", pendingTx.hash);
|
||||||
|
|
||||||
|
// Update lastAttempt
|
||||||
|
this.lastPushAttempt = {
|
||||||
|
nonce: Number(pendingTx.sequence_number),
|
||||||
|
gasPrice: gasUnitPrice,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error("Error executing messages");
|
||||||
|
console.log(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
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 { AptosPriceListener, AptosPricePusher } from "./aptos";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
command: "aptos",
|
||||||
|
describe: "run price pusher for aptos",
|
||||||
|
builder: {
|
||||||
|
endpoint: {
|
||||||
|
description:
|
||||||
|
"RPC endpoint endpoint URL for aptos. 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,
|
||||||
|
"override-gas-price-multiplier": {
|
||||||
|
description:
|
||||||
|
"Multiply the gas price by this number if the transaction is not landing to override it. Default 2",
|
||||||
|
type: "number",
|
||||||
|
required: false,
|
||||||
|
default: 2,
|
||||||
|
} as Options,
|
||||||
|
...options.priceConfigFile,
|
||||||
|
...options.priceServiceEndpoint,
|
||||||
|
...options.mnemonicFile,
|
||||||
|
...options.pythContractAddress,
|
||||||
|
...options.pollingFrequency,
|
||||||
|
...options.pushingFrequency,
|
||||||
|
},
|
||||||
|
handler: function (argv: any) {
|
||||||
|
// FIXME: type checks for this
|
||||||
|
const {
|
||||||
|
endpoint,
|
||||||
|
priceConfigFile,
|
||||||
|
priceServiceEndpoint,
|
||||||
|
mnemonicFile,
|
||||||
|
pythContractAddress,
|
||||||
|
pushingFrequency,
|
||||||
|
pollingFrequency,
|
||||||
|
overrideGasPriceMultiplier,
|
||||||
|
} = 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 aptosListener = new AptosPriceListener(
|
||||||
|
pythContractAddress,
|
||||||
|
endpoint,
|
||||||
|
priceItems,
|
||||||
|
{ pollingFrequency }
|
||||||
|
);
|
||||||
|
const aptosPusher = new AptosPricePusher(
|
||||||
|
priceServiceConnection,
|
||||||
|
pythContractAddress,
|
||||||
|
endpoint,
|
||||||
|
mnemonic,
|
||||||
|
overrideGasPriceMultiplier
|
||||||
|
);
|
||||||
|
|
||||||
|
const controller = new Controller(
|
||||||
|
priceConfigs,
|
||||||
|
pythListener,
|
||||||
|
aptosListener,
|
||||||
|
aptosPusher,
|
||||||
|
{ pushingFrequency }
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.start();
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
export type PushAttempt = {
|
||||||
|
nonce: number;
|
||||||
|
gasPrice: number;
|
||||||
|
};
|
|
@ -18,6 +18,7 @@ import {
|
||||||
} from "@pythnetwork/price-service-client";
|
} from "@pythnetwork/price-service-client";
|
||||||
import { CustomGasStation } from "./custom-gas-station";
|
import { CustomGasStation } from "./custom-gas-station";
|
||||||
import { Provider } from "web3/providers";
|
import { Provider } from "web3/providers";
|
||||||
|
import { PushAttempt } from "../common";
|
||||||
|
|
||||||
export class EvmPriceListener extends ChainPriceListener {
|
export class EvmPriceListener extends ChainPriceListener {
|
||||||
private pythContractFactory: PythContractFactory;
|
private pythContractFactory: PythContractFactory;
|
||||||
|
@ -117,11 +118,6 @@ export class EvmPriceListener extends ChainPriceListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PushAttempt = {
|
|
||||||
nonce: number;
|
|
||||||
gasPrice: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class EvmPricePusher implements IPricePusher {
|
export class EvmPricePusher implements IPricePusher {
|
||||||
private customGasStation?: CustomGasStation;
|
private customGasStation?: CustomGasStation;
|
||||||
private pythContract: Contract;
|
private pythContract: Contract;
|
||||||
|
|
|
@ -3,10 +3,12 @@ import yargs from "yargs";
|
||||||
import { hideBin } from "yargs/helpers";
|
import { hideBin } from "yargs/helpers";
|
||||||
import injective from "./injective/command";
|
import injective from "./injective/command";
|
||||||
import evm from "./evm/command";
|
import evm from "./evm/command";
|
||||||
|
import aptos from "./aptos/command";
|
||||||
|
|
||||||
yargs(hideBin(process.argv))
|
yargs(hideBin(process.argv))
|
||||||
.config("config")
|
.config("config")
|
||||||
.global("config")
|
.global("config")
|
||||||
.command(evm)
|
.command(evm)
|
||||||
.command(injective)
|
.command(injective)
|
||||||
|
.command(aptos)
|
||||||
.help().argv;
|
.help().argv;
|
||||||
|
|
Loading…
Reference in New Issue