1
1
import { DataSource } from "@pythnetwork/xc-admin-common" ;
2
2
import {
3
3
KeyValueConfig ,
4
+ Price ,
4
5
PriceFeed ,
5
6
PriceFeedContract ,
6
7
PrivateKey ,
7
8
TxResult ,
8
9
} from "../base" ;
9
10
import { Chain , StarknetChain } from "../chains" ;
10
- import { Contract } from "starknet" ;
11
+ import { Account , Contract , shortString } from "starknet" ;
12
+ import { ByteBuffer } from "@pythnetwork/pyth-starknet-js" ;
11
13
12
14
export class StarknetPriceFeedContract extends PriceFeedContract {
13
15
static type = "StarknetPriceFeedContract" ;
@@ -65,29 +67,146 @@ export class StarknetPriceFeedContract extends PriceFeedContract {
65
67
} ) ;
66
68
}
67
69
68
- getBaseUpdateFee ( ) : Promise < { amount : string ; denom ?: string | undefined } > {
69
- throw new Error ( "Method not implemented." ) ;
70
+ async getBaseUpdateFee ( ) : Promise < {
71
+ amount : string ;
72
+ denom ?: string | undefined ;
73
+ } > {
74
+ const tokens = await this . getFeeTokenAddresses ( ) ;
75
+ return await this . getBaseUpdateFeeInToken ( tokens [ 0 ] ) ;
70
76
}
71
- getLastExecutedGovernanceSequence ( ) : Promise < number > {
72
- throw new Error ( "Method not implemented." ) ;
77
+
78
+ /**
79
+ * Returns the list of accepted fee tokens.
80
+ * @returns hex encoded token addresses without 0x prefix
81
+ */
82
+ async getFeeTokenAddresses ( ) : Promise < string [ ] > {
83
+ const contract = await this . getContractClient ( ) ;
84
+ const tokens : bigint [ ] = await contract . fee_token_addresses ( ) ;
85
+ return tokens . map ( ( t ) => t . toString ( 16 ) ) ;
73
86
}
74
- getPriceFeed ( feedId : string ) : Promise < PriceFeed | undefined > {
75
- throw new Error ( "Method not implemented." ) ;
87
+
88
+ /**
89
+ * Returns the single update fee and symbol of the specified token.
90
+ * @param token hex encoded token address without 0x prefix
91
+ */
92
+ async getBaseUpdateFeeInToken (
93
+ token : string
94
+ ) : Promise < { amount : string ; denom ?: string | undefined } > {
95
+ token = "0x" + token ;
96
+ const provider = this . chain . getProvider ( ) ;
97
+ const contract = await this . getContractClient ( ) ;
98
+ const fee : bigint = await contract . get_single_update_fee ( token ) ;
99
+
100
+ const tokenClassData = await provider . getClassAt ( token ) ;
101
+ const tokenContract = new Contract ( tokenClassData . abi , token , provider ) ;
102
+ const denom = shortString . decodeShortString ( await tokenContract . symbol ( ) ) ;
103
+ return { amount : fee . toString ( ) , denom } ;
76
104
}
77
- executeUpdatePriceFeed (
105
+
106
+ async getLastExecutedGovernanceSequence ( ) : Promise < number > {
107
+ const contract = await this . getContractClient ( ) ;
108
+ return Number ( await contract . last_executed_governance_sequence ( ) ) ;
109
+ }
110
+
111
+ async getPriceFeed ( feedId : string ) : Promise < PriceFeed | undefined > {
112
+ const contract = await this . getContractClient ( ) ;
113
+ const result = await contract . query_price_feed_unsafe ( "0x" + feedId ) ;
114
+ console . log ( result ) ;
115
+ if ( result . Ok !== undefined ) {
116
+ return {
117
+ price : convertPrice ( result . Ok . price ) ,
118
+ emaPrice : convertPrice ( result . Ok . ema_price ) ,
119
+ } ;
120
+ } else {
121
+ throw new Error ( JSON . stringify ( result . Err ) ) ;
122
+ }
123
+ }
124
+
125
+ async executeUpdatePriceFeed (
78
126
senderPrivateKey : PrivateKey ,
79
127
vaas : Buffer [ ]
80
128
) : Promise < TxResult > {
81
- throw new Error ( "Method not implemented." ) ;
129
+ // We need the account address to send transactions.
130
+ throw new Error ( "Use executeUpdatePriceFeedWithAddress instead" ) ;
82
131
}
132
+
133
+ /**
134
+ * Executes the update instructions contained in the VAAs using the sender credentials
135
+ * @param senderPrivateKey private key of the sender in hex format without 0x prefix
136
+ * @param senderAddress address of the sender's account in hex format without 0x prefix
137
+ * @param vaa VAA containing price update messages to execute
138
+ */
139
+ async executeUpdatePriceFeedWithAddress (
140
+ senderPrivateKey : PrivateKey ,
141
+ senderAddress : string ,
142
+ vaa : Buffer
143
+ ) : Promise < TxResult > {
144
+ const provider = this . chain . getProvider ( ) ;
145
+ const contract = await this . getContractClient ( ) ;
146
+ const account = new Account (
147
+ provider ,
148
+ "0x" + senderAddress ,
149
+ "0x" + senderPrivateKey
150
+ ) ;
151
+ contract . connect ( account ) ;
152
+
153
+ const feeToken = "0x" + ( await this . getFeeTokenAddresses ( ) ) [ 0 ] ;
154
+ const tokenClassData = await provider . getClassAt ( feeToken ) ;
155
+ const tokenContract = new Contract ( tokenClassData . abi , feeToken , provider ) ;
156
+ tokenContract . connect ( account ) ;
157
+
158
+ const updateData = ByteBuffer . fromBuffer ( vaa ) ;
159
+ const feeAmount = await contract . get_update_fee ( updateData , feeToken ) ;
160
+ const feeTx = await tokenContract . approve ( this . address , feeAmount ) ;
161
+ await provider . waitForTransaction ( feeTx . transaction_hash ) ;
162
+
163
+ const tx = await contract . update_price_feeds ( updateData ) ;
164
+ const info = await provider . waitForTransaction ( tx . transaction_hash ) ;
165
+ return { id : tx . transaction_hash , info } ;
166
+ }
167
+
83
168
executeGovernanceInstruction (
84
169
senderPrivateKey : PrivateKey ,
85
170
vaa : Buffer
86
171
) : Promise < TxResult > {
87
- throw new Error ( "Method not implemented." ) ;
172
+ // We need the account address to send transactions.
173
+ throw new Error ( "Use executeGovernanceInstructionWithAddress instead" ) ;
174
+ }
175
+
176
+ /**
177
+ * Executes the governance instruction contained in the VAA using the sender credentials
178
+ * @param senderPrivateKey private key of the sender in hex format without 0x prefix
179
+ * @param senderAddress address of the sender's account in hex format without 0x prefix
180
+ * @param vaa the VAA to execute
181
+ */
182
+ async executeGovernanceInstructionWithAddress (
183
+ senderPrivateKey : PrivateKey ,
184
+ senderAddress : string ,
185
+ vaa : Buffer
186
+ ) : Promise < TxResult > {
187
+ const provider = this . chain . getProvider ( ) ;
188
+ const contract = await this . getContractClient ( ) ;
189
+ const account = new Account (
190
+ provider ,
191
+ "0x" + senderAddress ,
192
+ "0x" + senderPrivateKey
193
+ ) ;
194
+ contract . connect ( account ) ;
195
+
196
+ const updateData = ByteBuffer . fromBuffer ( vaa ) ;
197
+ const tx = await contract . execute_governance_instruction ( updateData ) ;
198
+ const info = await provider . waitForTransaction ( tx . transaction_hash ) ;
199
+ return { id : tx . transaction_hash , info } ;
88
200
}
89
- getGovernanceDataSource ( ) : Promise < DataSource > {
90
- throw new Error ( "Method not implemented." ) ;
201
+
202
+ async getGovernanceDataSource ( ) : Promise < DataSource > {
203
+ const contract = await this . getContractClient ( ) ;
204
+ const source : { emitter_chain_id : bigint ; emitter_address : bigint } =
205
+ await contract . governance_data_source ( ) ;
206
+ return {
207
+ emitterChain : Number ( source . emitter_chain_id ) ,
208
+ emitterAddress : source . emitter_address . toString ( 16 ) ,
209
+ } ;
91
210
}
92
211
93
212
getId ( ) : string {
@@ -98,3 +217,17 @@ export class StarknetPriceFeedContract extends PriceFeedContract {
98
217
return StarknetPriceFeedContract . type ;
99
218
}
100
219
}
220
+
221
+ function convertPrice ( obj : {
222
+ price : bigint ;
223
+ conf : bigint ;
224
+ expo : bigint ;
225
+ publish_time : bigint ;
226
+ } ) : Price {
227
+ return {
228
+ price : obj . price . toString ( ) ,
229
+ conf : obj . conf . toString ( ) ,
230
+ expo : obj . expo . toString ( ) ,
231
+ publishTime : obj . publish_time . toString ( ) ,
232
+ } ;
233
+ }
0 commit comments