-
Notifications
You must be signed in to change notification settings - Fork 195
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
431 additions
and
537 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,328 @@ | ||
import { | ||
Address, | ||
beginCell, | ||
Cell, | ||
Contract, | ||
ContractProvider, | ||
Dictionary, | ||
Sender, | ||
SendMode, | ||
toNano, | ||
} from "@ton/core"; | ||
import { createCellChain } from "../tests/utils"; | ||
import { createGuardianSetsDict } from "../tests/utils/wormhole"; | ||
import { HexString, Price } from "@pythnetwork/price-service-sdk"; | ||
import { DataSource } from "@pythnetwork/xc-admin-common"; | ||
|
||
export class BaseWrapper implements Contract { | ||
constructor( | ||
readonly address: Address, | ||
readonly init?: { code: Cell; data: Cell } | ||
) {} | ||
|
||
static createFromAddress(address: Address) { | ||
return new this(address); | ||
} | ||
|
||
static createInitData(config: { | ||
priceFeedId?: HexString; | ||
timePeriod?: number; | ||
price?: Price; | ||
emaPrice?: Price; | ||
singleUpdateFee?: number; | ||
dataSources?: DataSource[]; | ||
guardianSetIndex: number; | ||
guardianSet: string[]; | ||
chainId: number; | ||
governanceChainId: number; | ||
governanceContract: string; | ||
governanceDataSource?: DataSource; | ||
}): Cell { | ||
const priceDict = Dictionary.empty( | ||
Dictionary.Keys.BigUint(256), | ||
Dictionary.Values.Cell() | ||
); | ||
|
||
if ( | ||
config.priceFeedId && | ||
config.price && | ||
config.emaPrice && | ||
config.timePeriod | ||
) { | ||
const priceCell = beginCell() | ||
.storeInt( | ||
config.price.getPriceAsNumberUnchecked() * 10 ** -config.price.expo, | ||
64 | ||
) | ||
.storeUint( | ||
config.price.getConfAsNumberUnchecked() * 10 ** -config.price.expo, | ||
64 | ||
) | ||
.storeInt(config.price.expo, 32) | ||
.storeUint(config.price.publishTime, 64) | ||
.endCell(); | ||
|
||
const emaPriceCell = beginCell() | ||
.storeInt( | ||
config.emaPrice.getPriceAsNumberUnchecked() * | ||
10 ** -config.emaPrice.expo, | ||
64 | ||
) | ||
.storeUint( | ||
config.emaPrice.getConfAsNumberUnchecked() * | ||
10 ** -config.emaPrice.expo, | ||
64 | ||
) | ||
.storeInt(config.emaPrice.expo, 32) | ||
.storeUint(config.emaPrice.publishTime, 64) | ||
.endCell(); | ||
|
||
const priceFeedCell = beginCell() | ||
.storeRef(priceCell) | ||
.storeRef(emaPriceCell) | ||
.storeUint(config.timePeriod, 32) | ||
.endCell(); | ||
|
||
priceDict.set(BigInt(config.priceFeedId), priceFeedCell); | ||
} | ||
|
||
// Create a dictionary for data sources | ||
const dataSourcesDict = Dictionary.empty( | ||
Dictionary.Keys.Uint(32), | ||
Dictionary.Values.Cell() | ||
); | ||
// Create a dictionary for valid data sources | ||
const isValidDataSourceDict = Dictionary.empty( | ||
Dictionary.Keys.BigUint(256), | ||
Dictionary.Values.Bool() | ||
); | ||
|
||
if (config.dataSources) { | ||
config.dataSources.forEach((source, index) => { | ||
const sourceCell = beginCell() | ||
.storeUint(source.emitterChain, 16) | ||
.storeBuffer(Buffer.from(source.emitterAddress, "hex")) | ||
.endCell(); | ||
dataSourcesDict.set(index, sourceCell); | ||
const cellHash = BigInt("0x" + sourceCell.hash().toString("hex")); | ||
isValidDataSourceDict.set(cellHash, true); | ||
}); | ||
} | ||
|
||
// Group price feeds and update fee | ||
const priceFeedsCell = beginCell() | ||
.storeDict(priceDict) | ||
.storeUint(config.singleUpdateFee || 0, 256) | ||
.endCell(); | ||
|
||
// Group data sources information | ||
const dataSourcesCell = beginCell() | ||
.storeDict(dataSourcesDict) | ||
.storeUint(config.dataSources ? config.dataSources.length : 0, 32) | ||
.storeDict(isValidDataSourceDict) | ||
.endCell(); | ||
|
||
// Group guardian set information | ||
const guardianSetCell = beginCell() | ||
.storeUint(config.guardianSetIndex, 32) | ||
.storeDict( | ||
createGuardianSetsDict(config.guardianSet, config.guardianSetIndex) | ||
) | ||
.endCell(); | ||
|
||
// Group chain and governance information | ||
const governanceCell = beginCell() | ||
.storeUint(config.chainId, 16) | ||
.storeUint(config.governanceChainId, 16) | ||
.storeBuffer(Buffer.from(config.governanceContract, "hex")) | ||
.storeDict(Dictionary.empty()) // consumed_governance_actions | ||
.storeRef( | ||
config.governanceDataSource | ||
? beginCell() | ||
.storeUint(config.governanceDataSource.emitterChain, 16) | ||
.storeBuffer( | ||
Buffer.from(config.governanceDataSource.emitterAddress, "hex") | ||
) | ||
.endCell() | ||
: beginCell().endCell() | ||
) // governance_data_source | ||
.storeUint(0, 64) // last_executed_governance_sequence, set to 0 for initial state | ||
.storeUint(0, 32) // governance_data_source_index, set to 0 for initial state | ||
.storeUint(0, 256) // upgrade_code_hash, set to 0 for initial state | ||
.endCell(); | ||
|
||
// Create the main cell with references to grouped data | ||
return beginCell() | ||
.storeRef(priceFeedsCell) | ||
.storeRef(dataSourcesCell) | ||
.storeRef(guardianSetCell) | ||
.storeRef(governanceCell) | ||
.endCell(); | ||
} | ||
|
||
async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { | ||
await provider.internal(via, { | ||
value, | ||
sendMode: SendMode.PAY_GAS_SEPARATELY, | ||
body: beginCell().endCell(), | ||
}); | ||
} | ||
|
||
async getCurrentGuardianSetIndex( | ||
provider: ContractProvider, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, []); | ||
return result.stack.readNumber(); | ||
} | ||
|
||
async sendUpdateGuardianSet( | ||
provider: ContractProvider, | ||
via: Sender, | ||
vm: Buffer | ||
) { | ||
const messageBody = beginCell() | ||
.storeUint(1, 32) // OP_UPDATE_GUARDIAN_SET | ||
.storeRef(createCellChain(vm)) | ||
.endCell(); | ||
|
||
await provider.internal(via, { | ||
value: toNano("0.1"), | ||
sendMode: SendMode.PAY_GAS_SEPARATELY, | ||
body: messageBody, | ||
}); | ||
} | ||
|
||
async sendUpdatePriceFeeds( | ||
provider: ContractProvider, | ||
via: Sender, | ||
updateData: Buffer, | ||
updateFee: bigint | ||
) { | ||
const messageBody = beginCell() | ||
.storeUint(2, 32) // OP_UPDATE_PRICE_FEEDS | ||
.storeRef(createCellChain(updateData)) | ||
.endCell(); | ||
|
||
await provider.internal(via, { | ||
value: updateFee, | ||
sendMode: SendMode.PAY_GAS_SEPARATELY, | ||
body: messageBody, | ||
}); | ||
} | ||
|
||
async getChainId(provider: ContractProvider, methodName: string) { | ||
const result = await provider.get(methodName, []); | ||
return result.stack.readNumber(); | ||
} | ||
|
||
async getPriceUnsafe( | ||
provider: ContractProvider, | ||
priceFeedId: HexString, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, [ | ||
{ type: "int", value: BigInt(priceFeedId) }, | ||
]); | ||
|
||
const price = result.stack.readNumber(); | ||
const conf = result.stack.readNumber(); | ||
const expo = result.stack.readNumber(); | ||
const publishTime = result.stack.readNumber(); | ||
|
||
return { | ||
price, | ||
conf, | ||
expo, | ||
publishTime, | ||
}; | ||
} | ||
|
||
async getPriceNoOlderThan( | ||
provider: ContractProvider, | ||
timePeriod: number, | ||
priceFeedId: HexString, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, [ | ||
{ type: "int", value: BigInt(timePeriod) }, | ||
{ type: "int", value: BigInt(priceFeedId) }, | ||
]); | ||
|
||
const price = result.stack.readNumber(); | ||
const conf = result.stack.readNumber(); | ||
const expo = result.stack.readNumber(); | ||
const publishTime = result.stack.readNumber(); | ||
|
||
return { | ||
price, | ||
conf, | ||
expo, | ||
publishTime, | ||
}; | ||
} | ||
|
||
async getEmaPriceUnsafe( | ||
provider: ContractProvider, | ||
priceFeedId: HexString, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, [ | ||
{ type: "int", value: BigInt(priceFeedId) }, | ||
]); | ||
|
||
const price = result.stack.readNumber(); | ||
const conf = result.stack.readNumber(); | ||
const expo = result.stack.readNumber(); | ||
const publishTime = result.stack.readNumber(); | ||
|
||
return { | ||
price, | ||
conf, | ||
expo, | ||
publishTime, | ||
}; | ||
} | ||
|
||
async getEmaPriceNoOlderThan( | ||
provider: ContractProvider, | ||
timePeriod: number, | ||
priceFeedId: HexString, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, [ | ||
{ type: "int", value: BigInt(timePeriod) }, | ||
{ type: "int", value: BigInt(priceFeedId) }, | ||
]); | ||
|
||
const price = result.stack.readNumber(); | ||
const conf = result.stack.readNumber(); | ||
const expo = result.stack.readNumber(); | ||
const publishTime = result.stack.readNumber(); | ||
|
||
return { | ||
price, | ||
conf, | ||
expo, | ||
publishTime, | ||
}; | ||
} | ||
|
||
async getUpdateFee( | ||
provider: ContractProvider, | ||
vm: Buffer, | ||
methodName: string | ||
) { | ||
const result = await provider.get(methodName, [ | ||
{ type: "slice", cell: createCellChain(vm) }, | ||
]); | ||
|
||
return result.stack.readNumber(); | ||
} | ||
|
||
async getSingleUpdateFee(provider: ContractProvider, methodName: string) { | ||
const result = await provider.get(methodName, []); | ||
|
||
return result.stack.readNumber(); | ||
} | ||
} |
Oops, something went wrong.