diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0f505a0ba..b0e115afa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,5 +51,12 @@ jobs: shell: bash run: yarn validator & sleep 3 + - name: Logs + continue-on-error: false + shell: bash + run: yarn validator:logs & sleep 3 + - name: Test run: yarn test + + diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 75b41a62d..44503af8d 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,30 @@ # @convergence-rfq/cli +## 6.1.0 + +### Minor Changes + +- Remove collateral requirements, add quote spot fees, add spot instrument config, remove operations to unlock collateral or settle defaults + +### Patch Changes + +- Updated dependencies + - @convergence-rfq/sdk@6.1.0 + +## 6.0.1 + +### Patch Changes + +- Updated dependencies + - @convergence-rfq/sdk@6.0.1 + +## 6.0.0 + +### Patch Changes + +- Updated dependencies + - @convergence-rfq/sdk@6.0.0 + ## 4.5.35 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 3c4e1e7df..c82ff97e9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@convergence-rfq/cli", "description": "Official Convergence CLI", - "version": "4.5.35", + "version": "6.1.0", "license": "MIT", "publishConfig": { "access": "public" @@ -47,7 +47,7 @@ "cli": "ts-node src/index.ts" }, "dependencies": { - "@convergence-rfq/sdk": "4.5.35", + "@convergence-rfq/sdk": "6.1.0", "@solana/web3.js": "^1.87.6", "@types/cookie": "^0.5.1", "commander": "^10.0.0" diff --git a/packages/cli/scripts/bootstrap.sh b/packages/cli/scripts/bootstrap.sh index be9e1d569..41186e487 100755 --- a/packages/cli/scripts/bootstrap.sh +++ b/packages/cli/scripts/bootstrap.sh @@ -4,9 +4,10 @@ set -e export DEVNET="true" -export SPOT_INSTRUMENT="CjQCEjXtG3QNBuT5Z1sctaAYCo5Mt6edftqHQetEPo9w" -export PSYOPTIONS_EUROPEAN_INSTRUMENT="A86fhhdNVDdXV8pB48WXtPeM3EBkcBeJEdrx9xrUo9nF" -export PSYOPTIONS_AMERICAN_INSTRUMENT="6JG1tWK4w6LmjeXbmDZJsmUsPSjgnp74j2XPsTvjjTX8" +export SPOT_INSTRUMENT="4A9M7iojGDPc4n4YDGnTmsYsNKUohG1zM1nrAqVMMmrm" +export PSYOPTIONS_EUROPEAN_INSTRUMENT="6B7TdBNAF7tWWz5sZbbBZj8jH1ix7QWAchtkvMHveEuW" +export PSYOPTIONS_AMERICAN_INSTRUMENT="HGmSFSRfVAG8RC8Ae4G1JFSHK7Au5GrGskDxncG3JRok" +export HXRO_PRINT_TRADE_PROVIDER="4WbVwc5Edfo3oB1n16bVC9qrghYHSNh1qAECbSCyiT95" # Same for devnet and mainnet export BTC_ORACLE_ADDRESS="8SXvChNYFhRq4EZuZvnhjrB3jJRQCv4k3P4W6hesH3Ee" @@ -31,6 +32,12 @@ convergence protocol initialize --collateral-mint=$USDC_MINT --rpc-endpoint=$RPC convergence risk-engine initialize --rpc-endpoint=$RPC_ENDPOINT +convergence protocol add-print-trade-provider --print-trade-provider-program $HXRO_PRINT_TRADE_PROVIDER --settlement-can-expire false --validate-response-account-amount 2 --rpc-endpoint=$RPC_ENDPOINT +convergence hxro initialize-config --valid-mpg $HXRO_MPG --rpc-endpoint=$RPC_ENDPOINT +convergence hxro initialize-operator-trg --rpc-endpoint=$RPC_ENDPOINT + +convergence spot-instrument initialize-config --fee-bps "0.01" --rpc-endpoint=$RPC_ENDPOINT + convergence protocol add-instrument --instrument-program=$SPOT_INSTRUMENT --can-be-used-as-quote=true --validate-data-account-amount=1 --prepare-to-settle-account-amount=7 --settle-account-amount=3 --revert-preparation-account-amount=3 --clean-up-account-amount=4 --rpc-endpoint=$RPC_ENDPOINT convergence protocol add-instrument --instrument-program=$PSYOPTIONS_EUROPEAN_INSTRUMENT --can-be-used-as-quote=false --validate-data-account-amount=2 --prepare-to-settle-account-amount=7 --settle-account-amount=3 --revert-preparation-account-amount=3 --clean-up-account-amount=4 --rpc-endpoint=$RPC_ENDPOINT convergence protocol add-instrument --instrument-program=$PSYOPTIONS_AMERICAN_INSTRUMENT --can-be-used-as-quote=false --validate-data-account-amount=3 --prepare-to-settle-account-amount=7 --settle-account-amount=3 --revert-preparation-account-amount=3 --clean-up-account-amount=4 --rpc-endpoint=$RPC_ENDPOINT diff --git a/packages/cli/src/actions.ts b/packages/cli/src/actions.ts index 373d0ed2e..bcfb783a0 100644 --- a/packages/cli/src/actions.ts +++ b/packages/cli/src/actions.ts @@ -7,6 +7,8 @@ import { PriceOracle, SpotLegInstrument, SpotQuoteInstrument, + isRiskCategory, + isOracleSource, addBaseAssetBuilder, registerMintBuilder, TransactionBuilder, @@ -16,7 +18,7 @@ import { createCvg, Opts } from './cvg'; import { fetchBirdeyeTokenPrice, fetchCoinGeckoTokenPrice, - getInstrumentType, + extractBooleanString, getSigConfirmation, getSize, } from './helpers'; @@ -128,7 +130,7 @@ export const addInstrument = async (opts: Opts) => { const { response } = await cvg.protocol().addInstrument({ authority: cvg.rpc().getDefaultFeePayer(), instrumentProgram: new PublicKey(opts.instrumentProgram), - canBeUsedAsQuote: opts.canBeUsedAsQuote, + canBeUsedAsQuote: extractBooleanString(opts, 'canBeUsedAsQuote'), validateDataAccountAmount: opts.validateDataAccountAmount, prepareToSettleAccountAmount: opts.prepareToSettleAccountAmount, settleAccountAmount: opts.settleAccountAmount, @@ -141,6 +143,20 @@ export const addInstrument = async (opts: Opts) => { } }; +export const addPrintTradeProvider = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const { response } = await cvg.protocol().addPrintTradeProvider({ + printTradeProviderProgram: new PublicKey(opts.printTradeProviderProgram), + settlementCanExpire: extractBooleanString(opts, 'settlementCanExpire'), + validateResponseAccountAmount: opts.validateResponseAccountAmount, + }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + export const addBaseAsset = async (opts: Opts) => { const cvg = await createCvg(opts); try { @@ -173,6 +189,85 @@ export const addBaseAsset = async (opts: Opts) => { } }; +export const changeBaseAssetParameters = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const { + index, + enabled: enabledOpts, + riskCategory, + oracleSource, + switchboardOracle: switchboardOracleOpts, + pythOracle: pythOracleOpts, + inPlacePrice: inPlacePriceOpts, + }: { + index: number; + enabled?: string; + riskCategory?: string; + oracleSource?: string; + switchboardOracle?: string; + pythOracle?: string; + inPlacePrice?: number; + } = opts; + + let enabled; + switch (enabledOpts) { + case undefined: + break; + case 'true': + enabled = true; + break; + case 'false': + enabled = false; + break; + default: + throw new Error('Unrecognized enabled parameter!'); + } + + if (riskCategory !== undefined && !isRiskCategory(riskCategory)) { + throw new Error('Unrecognized risk category parameter!'); + } + + if (oracleSource !== undefined && !isOracleSource(oracleSource)) { + throw new Error('Unrecognized oracle source parameter!'); + } + + let switchboardOracle; + if (switchboardOracleOpts === 'none') { + switchboardOracle = null; + } else if (typeof switchboardOracleOpts === 'string') { + switchboardOracle = new PublicKey(switchboardOracleOpts); + } + + let pythOracle; + if (pythOracleOpts === 'none') { + pythOracle = null; + } else if (typeof pythOracleOpts === 'string') { + pythOracle = new PublicKey(pythOracleOpts); + } + + let inPlacePrice; + if (inPlacePriceOpts === -1) { + inPlacePrice = null; + } else if (typeof inPlacePriceOpts === 'number') { + inPlacePrice = inPlacePriceOpts; + } + + const { response } = await cvg.protocol().changeBaseAssetParameters({ + index, + enabled, + riskCategory, + oracleSource, + switchboardOracle, + pythOracle, + inPlacePrice, + }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + export const updateBaseAsset = async (opts: Opts) => { const cvg = await createCvg(opts); const { @@ -443,7 +538,7 @@ export const setRiskEngineInstrumentType = async (opts: Opts) => { try { const { response } = await cvg.riskEngine().setInstrumentType({ instrumentProgram: new PublicKey(opts.program), - instrumentType: getInstrumentType(opts.type), + instrumentType: opts.type, }); logResponse(response); } catch (e) { diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index f636038ef..860f86830 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -7,6 +7,8 @@ import { airdropGroup, rfqGroup, tokenGroup, + hxroGroup, + spotInstrumentGroup, } from './groups'; export const makeCli = (): Command => { @@ -17,6 +19,8 @@ export const makeCli = (): Command => { riskEngineGroup, collateralGroup, rfqGroup, + hxroGroup, + spotInstrumentGroup, ]; const cli = new Command(); diff --git a/packages/cli/src/cvg.ts b/packages/cli/src/cvg.ts index 7f45adb56..d8c098764 100644 --- a/packages/cli/src/cvg.ts +++ b/packages/cli/src/cvg.ts @@ -11,8 +11,7 @@ export const createCvg = async (opts: Opts): Promise => { new Connection(opts.rpcEndpoint, { commitment: 'confirmed', }), - - { transactionPriority: opts?.txPriority ?? 'none', skipPreflight: false } + { skipPreflight: opts.skipPreflight } ); cvg.use(keypairIdentity(user)); return cvg; diff --git a/packages/cli/src/groups/hxro.ts b/packages/cli/src/groups/hxro.ts new file mode 100644 index 000000000..f1a505766 --- /dev/null +++ b/packages/cli/src/groups/hxro.ts @@ -0,0 +1,120 @@ +/* eslint-disable no-console */ + +import { Command } from 'commander'; + +import { PublicKey } from '@solana/web3.js'; +import { HxroProductInfo } from '@convergence-rfq/sdk'; +import { addCmd } from '../helpers'; +import { createCvg, Opts } from '../cvg'; +import { logError, logHxroConfig, logResponse } from '../logger'; + +const initializeConfigCmd = (c: Command) => + addCmd(c, 'initialize-config', 'initializes hxro config', initializeConfig, [ + { + flags: '--valid-mpg ', + description: 'Valid Hxro market product group', + }, + ]); + +const initializeConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const response = await cvg + .hxro() + .initializeConfig({ validMpg: new PublicKey(opts.validMpg) }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + +const modifyConfigCmd = (c: Command) => + addCmd(c, 'modify-config', 'modifiess hxro config', modifyConfig, [ + { + flags: '--valid-mpg ', + description: 'Valid Hxro market product group', + }, + ]); + +const modifyConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const response = await cvg + .hxro() + .modifyConfig({ validMpg: new PublicKey(opts.validMpg) }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + +const displayConfigCmd = (c: Command) => + addCmd(c, 'display-config', 'displays hxro config', displayConfig, []); + +const displayConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const config = await cvg.hxro().fetchConfig(); + logHxroConfig(config); + } catch (e) { + logError(e); + } +}; + +const displayProductsCmd = (c: Command) => + addCmd(c, 'display-products', 'displays hxro products', displayProducts, []); + +const displayProducts = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const products: HxroProductInfo[] = await cvg.hxro().fetchProducts(); + console.log(`Products amount: ${products.length}`); + products.forEach((product) => { + console.log(JSON.stringify(product)); + }); + } catch (e) { + logError(e); + } +}; + +const initializeOperatorTRGCmd = (c: Command) => + addCmd( + c, + 'initialize-operator-trg', + 'initialized a trg for an operator, which is required for hxro settlements', + initializeOperatorTRG, + [ + { + flags: '--hxro-risk-engine ', + description: + 'Overrides hxro risk engine address. Should be used primarely for testing purposes', + defaultValue: '', + }, + ] + ); + +const initializeOperatorTRG = async (opts: Opts) => { + const cvg = await createCvg(opts); + + try { + const hxroRiskEngineAddress = + opts.hxroRiskEngine !== '' + ? new PublicKey(opts.hxroRiskEngine) + : undefined; + const response = await cvg.hxro().initializeOperatorTraderRiskGroup({ + hxroRiskEngineAddress, + }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + +export const hxroGroup = (c: Command) => { + const group = c.command('hxro'); + initializeConfigCmd(group); + modifyConfigCmd(group); + displayConfigCmd(group); + initializeOperatorTRGCmd(group); + displayProductsCmd(group); +}; diff --git a/packages/cli/src/groups/index.ts b/packages/cli/src/groups/index.ts index 5d71fa882..ca0333b87 100644 --- a/packages/cli/src/groups/index.ts +++ b/packages/cli/src/groups/index.ts @@ -4,3 +4,5 @@ export * from './protocol'; export * from './rfq'; export * from './riskEngine'; export * from './token'; +export * from './hxro'; +export * from './spotInstrument'; diff --git a/packages/cli/src/groups/protocol.ts b/packages/cli/src/groups/protocol.ts index 40fddeb8a..b42cfab83 100644 --- a/packages/cli/src/groups/protocol.ts +++ b/packages/cli/src/groups/protocol.ts @@ -8,6 +8,8 @@ import { getProtocol, getBaseAssets, closeProtocol, + addPrintTradeProvider, + changeBaseAssetParameters, addBaseAssetsFromJupiter, updateBaseAsset, } from '../actions'; @@ -82,6 +84,28 @@ const addInstrumentCmd = (c: Command) => commonOptions ); +const addPrintTradeProviderCmd = (c: Command) => + addCmd( + c, + 'add-print-trade-provider', + 'adds print trade provider to the protocol', + addPrintTradeProvider, + [ + { + flags: '--print-trade-provider-program ', + description: 'print trade provider program address', + }, + { + flags: '--settlement-can-expire ', + description: 'settlement can expire', + }, + { + flags: '--validate-response-account-amount ', + description: 'amount of account passed to validate response CPI call', + }, + ] + ); + const closeCmd = (c: Command) => addCmd(c, 'close', 'closes protocol configuration', closeProtocol); @@ -113,6 +137,51 @@ const addBaseAssetCmd = (c: Command) => }, ]); +const changeBaseAssetParametersCmd = (c: Command) => + addCmd( + c, + 'change-base-asset-parameters', + 'change existing base asset parameters', + changeBaseAssetParameters, + [ + { + flags: '--index ', + description: 'base asset index', + }, + { + flags: '--enabled ', + description: 'true to enable base asset, false to disable', + defaultValue: null, + }, + { + flags: '--risk-category ', + description: 'risk category', + defaultValue: null, + }, + { + flags: '--oracle-source ', + description: 'oracle source', + defaultValue: null, + }, + { + flags: '--switchboard-oracle ', + description: 'switchboard oracle, none to unset', + defaultValue: null, + }, + { + flags: '--pyth-oracle ', + description: 'pyth oracle, none to unset', + defaultValue: null, + }, + + { + flags: '--in-place-price ', + description: 'in place price, -1 to unset', + defaultValue: null, + }, + ] + ); + const registerMintCmd = (c: Command) => addCmd(c, 'register-mint', 'registers protocol mint', registerMint, [ { flags: '--mint ', description: 'mint address' }, @@ -192,7 +261,9 @@ export const protocolGroup = (c: Command) => { const group = c.command('protocol'); initializeProtocolCmd(group); addInstrumentCmd(group); + addPrintTradeProviderCmd(group); addBaseAssetCmd(group); + changeBaseAssetParametersCmd(group); registerMintCmd(group); getRegisteredMintsCmd(group); getCmd(group); diff --git a/packages/cli/src/groups/spotInstrument.ts b/packages/cli/src/groups/spotInstrument.ts new file mode 100644 index 000000000..9f63a0dd6 --- /dev/null +++ b/packages/cli/src/groups/spotInstrument.ts @@ -0,0 +1,79 @@ +/* eslint-disable no-console */ + +import { Command } from 'commander'; + +import { addCmd } from '../helpers'; +import { createCvg, Opts } from '../cvg'; +import { logError, logResponse, logSpotInstrumentConfig } from '../logger'; + +const initializeConfigCmd = (c: Command) => + addCmd( + c, + 'initialize-config', + 'initializes spot instrument config', + initializeConfig, + [ + { + flags: '--fee-bps ', + description: 'Quote fees, value of 0.01 means 1%', + }, + ] + ); + +const initializeConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const response = await cvg + .spotInstrument() + .initializeConfig({ feeBps: opts.feeBps }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + +const modifyConfigCmd = (c: Command) => + addCmd(c, 'modify-config', 'modifiess spot instrument config', modifyConfig, [ + { + flags: '--fee-bps ', + description: 'Quote fees, value of 0.01 means 1%', + }, + ]); + +const modifyConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const response = await cvg + .spotInstrument() + .modifyConfig({ feeBps: opts.feeBps }); + logResponse(response); + } catch (e) { + logError(e); + } +}; + +const displayConfigCmd = (c: Command) => + addCmd( + c, + 'display-config', + 'displays spot instrument config', + displayConfig, + [] + ); + +const displayConfig = async (opts: Opts) => { + const cvg = await createCvg(opts); + try { + const config = await cvg.spotInstrument().fetchConfig(); + logSpotInstrumentConfig(config); + } catch (e) { + logError(e); + } +}; + +export const spotInstrumentGroup = (c: Command) => { + const group = c.command('spot-instrument'); + initializeConfigCmd(group); + modifyConfigCmd(group); + displayConfigCmd(group); +}; diff --git a/packages/cli/src/helpers.ts b/packages/cli/src/helpers.ts index 4de470230..b3ac1eb1f 100644 --- a/packages/cli/src/helpers.ts +++ b/packages/cli/src/helpers.ts @@ -4,24 +4,13 @@ import { PsyoptionsEuropeanInstrument, LegInstrument, FixedSize, - InstrumentType, } from '@convergence-rfq/sdk'; import { Command } from 'commander'; import { Connection } from '@solana/web3.js'; import { CoinGeckoResponse, Instrument } from './types'; import { DEFAULT_KEYPAIR_FILE, DEFAULT_RPC_ENDPOINT } from './constants'; - -export const getInstrumentType = (type: string): InstrumentType => { - switch (type) { - case 'spot': - return InstrumentType.Spot; - case 'option': - return InstrumentType.Option; - default: - throw new Error('Invalid instrument type'); - } -}; +import { Opts } from './cvg'; export const getSize = (size: string, amount: number): FixedSize => { switch (size) { @@ -62,6 +51,7 @@ export const formatInstrument = (instrument: Instrument): string => { export const addDefaultArgs = (cmd: any) => { cmd.option('--rpc-endpoint ', 'RPC endpoint', DEFAULT_RPC_ENDPOINT); + cmd.option('--skip-preflight', 'skip preflight', false); cmd.option('--keypair-file ', 'keypair file', DEFAULT_KEYPAIR_FILE); cmd.option('--verbose ', 'verbose', false); return cmd; @@ -99,6 +89,17 @@ export const addCmd = ( return cmd; }; +export const extractBooleanString = (opts: Opts, name: string): boolean => { + const value = opts[name]; + if (value !== 'true' && value !== 'false') { + throw new Error( + `${name} parameter value should be either 'true' or 'false'` + ); + } + + return value === 'true' ? true : false; +}; + export const getSigConfirmation = async ( connection: Connection, tx: string diff --git a/packages/cli/src/logger.ts b/packages/cli/src/logger.ts index 806c8b6c1..61624e09b 100644 --- a/packages/cli/src/logger.ts +++ b/packages/cli/src/logger.ts @@ -13,6 +13,10 @@ import { SpotLegInstrument, PsyoptionsAmericanInstrument, PsyoptionsEuropeanInstrument, + toPriceOracle, + PrintTradeLeg, + HxroPrintTradeProviderConfig, + SpotInstrumentConfig, } from '@convergence-rfq/sdk'; import { formatInstrument, assertInstrument } from './helpers'; @@ -27,18 +31,21 @@ export const logPk = (p: PublicKey): void => l('Address:', p.toString()); export const logTx = (t: string): void => l('Tx:', t); -export const logInstrument = (i: LegInstrument): void => { - assertInstrument(i); - l('Instrument:', formatInstrument(i)); +export const logInstrument = (i: LegInstrument | PrintTradeLeg): void => { l('Amount:', N(i?.getAmount().toString())); l('Side:', i.getSide()); - if (i instanceof SpotLegInstrument) { - l('Decimals:', N(i?.decimals.toString())); - l('Mint:', i.mintAddress.toString()); - } else if (i instanceof PsyoptionsAmericanInstrument) { - l('Decimals:', N(PsyoptionsAmericanInstrument.decimals.toString())); - } else if (i instanceof PsyoptionsEuropeanInstrument) { - l('Decimals:', N(PsyoptionsEuropeanInstrument.decimals.toString())); + + if (i.legType == 'escrow') { + assertInstrument(i); + l('Instrument:', formatInstrument(i)); + if (i instanceof SpotLegInstrument) { + l('Decimals:', N(i?.decimals.toString())); + l('Mint:', i.mintAddress.toString()); + } else if (i instanceof PsyoptionsAmericanInstrument) { + l('Decimals:', N(PsyoptionsAmericanInstrument.decimals.toString())); + } else if (i instanceof PsyoptionsEuropeanInstrument) { + l('Decimals:', N(PsyoptionsEuropeanInstrument.decimals.toString())); + } } }; @@ -46,16 +53,17 @@ export const logResponse = (r: SendAndConfirmTransactionResponse): void => l('Tx:', r.signature); export const logBaseAsset = (b: BaseAsset): void => { + const priceOracle = toPriceOracle(b); l('Address:', b.address.toString()); l('Ticker:', b.ticker.toString()); l('Enabled:', b.enabled); l('Index:', b.index); l('Risk category:', b.riskCategory); - l('Oracle source:', b.priceOracle.source); - if (b.priceOracle.address) { - l('Oracle address:', b.priceOracle.address.toString()); - } else if (b.priceOracle.price) { - l('Oracle price:', b.priceOracle.price.toString()); + l('Oracle source:', priceOracle.source); + if (priceOracle.address) { + l('Oracle address:', priceOracle.address.toString()); + } else if (priceOracle.price) { + l('Oracle price:', priceOracle.price.toString()); } }; @@ -102,7 +110,14 @@ export const logProtocol = (p: Protocol): void => { l(`Maker fee: ${p.settleFees.makerBps.toString()} bps`); l(`Taker default fee: ${p.defaultFees.takerBps.toString()} bps`); l(`Maker default fee: ${p.defaultFees.makerBps.toString()} bps`); + l('Registered instruments:', p.instruments.length); p.instruments.map(logProtocolInstrument); + l('Registered print trade providers:', p.printTradeProviders.length); + p.printTradeProviders.map((x) => { + l('Print trade provider address:', x.programKey.toString()); + l('Settlement can expire:', x.settlementCanExpire); + l('Validate response account amount:', x.validateResponseAccountAmount); + }); }; export const logRiskEngineConfig = (r: any): void => { @@ -148,6 +163,8 @@ export const logRfq = (r: Rfq) => { l('Taker:', r.taker.toString()); l('Order type:', r.orderType); l('Size:', r.size.type === 'open' ? 'open' : 'fixed'); + if (r.model === 'escrowRfq') { + } l('Created:', new Date(created).toString()); l(`Active window: ${r.activeWindow} seconds`); l(`Settlement window: ${r.settlingWindow} seconds`); @@ -156,4 +173,20 @@ export const logRfq = (r: Rfq) => { l('Total responses:', r.totalResponses); l('Confirmed responses:', r.confirmedResponses); l('Cleared responses:', r.clearedResponses); + if (r.model === 'printTradeRfq') { + l( + 'Print trade provider:', + r.printTrade.getPrintTradeProviderProgramId().toString() + ); + } +}; + +export const logHxroConfig = (d: HxroPrintTradeProviderConfig) => { + l('Address:', d.address.toString()); + l('Valid Hxro market product group:', d.validMpg.toString()); +}; + +export const logSpotInstrumentConfig = (d: SpotInstrumentConfig) => { + l('Address:', d.address.toString()); + l('Quote fees:', d.feeBps.toString()); }; diff --git a/packages/cli/tests/helpers.ts b/packages/cli/tests/helpers.ts index c81836904..f3b5e82b7 100644 --- a/packages/cli/tests/helpers.ts +++ b/packages/cli/tests/helpers.ts @@ -9,6 +9,7 @@ export const CTX = new Ctx(); export const COLLATERAL_MINT = CTX.collateralMint; export const SWITCHBOARD_BTC_ORACLE = CTX.switchboardBTCOracle; export const PYTH_SOL_ORACLE = CTX.pythSOLOracle; +export const HXRO_MPG = CTX.hxroMpg; export const runCli = async (args: string[], user = 'dao') => { return await makeCli().parseAsync( diff --git a/packages/cli/tests/unit/hxro.spec.ts b/packages/cli/tests/unit/hxro.spec.ts new file mode 100644 index 000000000..922c0d533 --- /dev/null +++ b/packages/cli/tests/unit/hxro.spec.ts @@ -0,0 +1,38 @@ +import { expect } from 'expect'; +import sinon, { SinonStub } from 'sinon'; + +import { ADDRESS_LABEL, HXRO_MPG, TX_LABEL, runCli } from '../helpers'; +import { HXRO_RISK_ENGINE } from '../../../validator'; + +describe('unit.hxro', () => { + let stub: SinonStub; + + beforeEach(() => { + stub = sinon.stub(console, 'log'); + }); + + afterEach(() => { + stub.restore(); + }); + + it('display config', async () => { + await runCli(['hxro', 'display-config']); + expect(stub.args[0][0]).toEqual(ADDRESS_LABEL); + expect(stub.args[1][0]).toEqual('Valid Hxro market product group:'); + }); + + it('modify config', async () => { + await runCli(['hxro', 'modify-config', '--valid-mpg', HXRO_MPG.toString()]); + expect(stub.args[0][0]).toEqual(TX_LABEL); + }); + + it('initialize operator TRG', async () => { + await runCli([ + 'hxro', + 'initialize-operator-trg', + '--hxro-risk-engine', + HXRO_RISK_ENGINE, + ]); + expect(stub.args[0][0]).toEqual(TX_LABEL); + }); +}); diff --git a/packages/cli/tests/unit/protocol.spec.ts b/packages/cli/tests/unit/protocol.spec.ts index 5fbe4d0cc..543c0b4f1 100644 --- a/packages/cli/tests/unit/protocol.spec.ts +++ b/packages/cli/tests/unit/protocol.spec.ts @@ -4,6 +4,7 @@ import sinon, { SinonStub } from 'sinon'; import { PROGRAM_ADDRESS as SPOT_INSTRUMENT_PROGRAM_ADDRESS } from '@convergence-rfq/spot-instrument'; import { PROGRAM_ADDRESS as PSYOPTIONS_AMERICAN_INSTRUMENT_PROGRAM_ADDRESS } from '@convergence-rfq/psyoptions-american-instrument'; import { PROGRAM_ADDRESS as PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ADDRESS } from '@convergence-rfq/psyoptions-european-instrument'; +import { PROGRAM_ADDRESS as HXRO_PRINT_TRADE_PROVIDER_PROGRAM_ADDRESS } from '@convergence-rfq/hxro-print-trade-provider'; import { ADDRESS_LABEL, @@ -68,7 +69,7 @@ describe('unit.protocol', () => { '--prepare-to-settle-account-amount', '7', '--settle-account-amount', - '3', + '5', '--revert-preparation-account-amount', '3', '--clean-up-account-amount', @@ -121,6 +122,20 @@ describe('unit.protocol', () => { expect(stub.args[0][0]).toEqual(TX_LABEL); }); + it('add-print-trade-provider [hxro]', async () => { + await runCli([ + 'protocol', + 'add-print-trade-provider', + '--print-trade-provider-program', + HXRO_PRINT_TRADE_PROVIDER_PROGRAM_ADDRESS, + '--settlement-can-expire', + 'false', + '--validate-response-account-amount', + '2', + ]); + expect(stub.args[0][0]).toEqual(TX_LABEL); + }); + it('add-base-asset [switchboard]', async () => { // TODO: Add Pyth and In Place Price Oracle await runCli([ @@ -150,6 +165,20 @@ describe('unit.protocol', () => { expect(stub.args[0][0]).toEqual(TX_LABEL); }); + it('change-base-asset [switchboard]', async () => { + await runCli([ + 'protocol', + 'change-base-asset-parameters', + '--index', + '0', + '--enabled', + 'true', + '--in-place-price', + '42', + ]); + expect(stub.args[0][0]).toEqual(TX_LABEL); + }); + it('add-base-asset [pyth]', async () => { await runCli([ 'protocol', diff --git a/packages/cli/tests/unit/riskEngine.spec.ts b/packages/cli/tests/unit/riskEngine.spec.ts index 43e17389c..71b1c8188 100644 --- a/packages/cli/tests/unit/riskEngine.spec.ts +++ b/packages/cli/tests/unit/riskEngine.spec.ts @@ -80,7 +80,7 @@ describe('unit.riskEngine', () => { '--category', 'very-low', '--new-value', - '0.05,0.5,0.02,0.2,0.04,0.3,0.08,0.4,0.12,0.5,0.2,0.6,0.3,0.7', + '0,0,0,0,0,0,0,0,0,0,0,0,0,0', ]); expect(stub.args[0][0]).toEqual(TX_LABEL); }); @@ -92,7 +92,7 @@ describe('unit.riskEngine', () => { '--category', 'low', '--new-value', - '0.05,0.8,0.04,0.4,0.08,0.6,0.16,0.8,0.24,1.0,0.4,1.2,0.6,1.4', + '0,0,0,0,0,0,0,0,0,0,0,0,0,0', ]); expect(stub.args[0][0]).toEqual(TX_LABEL); }); @@ -104,7 +104,7 @@ describe('unit.riskEngine', () => { '--category', 'medium', '--new-value', - '0.05,1.2,0.06,0.6,0.12,0.9,0.24,1.2,0.36,1.5,0.6,1.8,0.9,2.1', + '0,0,0,0,0,0,0,0,0,0,0,0,0,0', ]); expect(stub.args[0][0]).toEqual(TX_LABEL); }); @@ -116,7 +116,7 @@ describe('unit.riskEngine', () => { '--category', 'high', '--new-value', - '0.05,2.4,0.08,0.8,0.16,1.2,0.32,1.6,0.48,2.0,0.8,2.4,1.2,2.8', + '0,0,0,0,0,0,0,0,0,0,0,0,0,0', ]); expect(stub.args[0][0]).toEqual(TX_LABEL); }); @@ -128,7 +128,7 @@ describe('unit.riskEngine', () => { '--category', 'very-high', '--new-value', - '0.05,5.0,0.10,1.0,0.20,1.5,0.40,2.0,0.60,2.5,1.0,3.0,1.5,3.5', + '0,0,0,0,0,0,0,0,0,0,0,0,0,0', ]); expect(stub.args[0][0]).toEqual(TX_LABEL); }); diff --git a/packages/cli/tests/unit/spotInstrument.spec.ts b/packages/cli/tests/unit/spotInstrument.spec.ts new file mode 100644 index 000000000..449d5a378 --- /dev/null +++ b/packages/cli/tests/unit/spotInstrument.spec.ts @@ -0,0 +1,27 @@ +import { expect } from 'expect'; +import sinon, { SinonStub } from 'sinon'; + +import { ADDRESS_LABEL, TX_LABEL, runCli } from '../helpers'; + +describe('unit.spotInstrument', () => { + let stub: SinonStub; + + beforeEach(() => { + stub = sinon.stub(console, 'log'); + }); + + afterEach(() => { + stub.restore(); + }); + + it('display config', async () => { + await runCli(['spot-instrument', 'display-config']); + expect(stub.args[0][0]).toEqual(ADDRESS_LABEL); + expect(stub.args[1][0]).toEqual('Quote fees:'); + }); + + it('modify config', async () => { + await runCli(['spot-instrument', 'modify-config', '--fee-bps', '0.01']); + expect(stub.args[0][0]).toEqual(TX_LABEL); + }); +}); diff --git a/packages/js/CHANGELOG.md b/packages/js/CHANGELOG.md index a38a2dbd4..479d32748 100644 --- a/packages/js/CHANGELOG.md +++ b/packages/js/CHANGELOG.md @@ -1,5 +1,23 @@ # @convergence-rfq/sdk +## 6.1.0 + +### Minor Changes + +- Remove collateral requirements, add quote spot fees, add spot instrument config, remove operations to unlock collateral or settle defaults + +## 6.0.1 + +### Patch Changes + +- update cpl packages + +## 6.0.0 + +### Minor Changes + +- Hxro integration + ## 4.5.35 ### Patch Changes diff --git a/packages/js/package.json b/packages/js/package.json index c8db68538..bda7cee54 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -1,7 +1,7 @@ { "name": "@convergence-rfq/sdk", "description": "Official Convergence RFQ SDK", - "version": "4.5.35", + "version": "6.1.0", "license": "MIT", "publishConfig": { "access": "public" @@ -48,15 +48,19 @@ }, "dependencies": { "@aws-crypto/sha256-js": "3.0.0", + "@babel/plugin-syntax-import-attributes": "^7.23.3", "@bundlr-network/client": "^0.8.8", "@convergence-rfq/beet": "0.7.10", "@convergence-rfq/beet-solana": "0.4.11", - "@convergence-rfq/psyoptions-american-instrument": "2.3.3", - "@convergence-rfq/psyoptions-european-instrument": "2.3.3", - "@convergence-rfq/rfq": "2.3.3", - "@convergence-rfq/risk-engine": "2.3.3", - "@convergence-rfq/spot-instrument": "2.3.3", - "@coral-xyz/borsh": "^0.26.0", + "@convergence-rfq/hxro-print-trade-provider": "3.8.0", + "@convergence-rfq/psyoptions-american-instrument": "3.8.0", + "@convergence-rfq/psyoptions-european-instrument": "3.8.0", + "@convergence-rfq/rfq": "3.8.0", + "@convergence-rfq/risk-engine": "3.8.0", + "@convergence-rfq/spot-instrument": "3.8.0", + "@coral-xyz/anchor": "^0.28.0", + "@coral-xyz/borsh": "^0.28.0", + "@hxronetwork/dexterity-ts": "1.6.16", "@mithraic-labs/psy-american": "^0.2.3", "@mithraic-labs/tokenized-euros": "^0.2.3", "@noble/ed25519": "^1.7.1", diff --git a/packages/js/src/plugins/corePlugins/plugin.ts b/packages/js/src/plugins/corePlugins/plugin.ts index ccb006f36..631c29b1a 100644 --- a/packages/js/src/plugins/corePlugins/plugin.ts +++ b/packages/js/src/plugins/corePlugins/plugin.ts @@ -15,6 +15,8 @@ import { instrumentModule } from '../instrumentModule'; import { psyoptionsEuropeanInstrumentModule } from '../psyoptionsEuropeanInstrumentModule'; import { psyoptionsAmericanInstrumentModule } from '../psyoptionsAmericanInstrumentModule'; import { spotInstrumentModule } from '../spotInstrumentModule'; +import { hxroModule } from '../hxroPrintTradeProviderModule'; +import { printTradeModule } from '../printTradeModule'; import { whitelistModule } from '../whitelistModule'; export const corePlugins = () => ({ @@ -41,8 +43,10 @@ export const corePlugins = () => ({ // Integrations convergence.use(instrumentModule()); + convergence.use(printTradeModule()); convergence.use(spotInstrumentModule()); convergence.use(psyoptionsEuropeanInstrumentModule()); convergence.use(psyoptionsAmericanInstrumentModule()); + convergence.use(hxroModule()); }, }); diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/accounts.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/accounts.ts new file mode 100644 index 000000000..7f46d86ea --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/accounts.ts @@ -0,0 +1,18 @@ +import { Config } from '@convergence-rfq/hxro-print-trade-provider'; + +import { + Account, + getAccountParsingAndAssertingFunction, + getAccountParsingFunction, +} from '../../types'; + +/** @group Accounts */ +export type HxroPrintTradeProviderConfigAccount = Account; + +/** @group Account Helpers */ +export const parseHxroPrintTradeProviderConfigAccount = + getAccountParsingFunction(Config); + +/** @group Account Helpers */ +export const toHxroPrintTradeProviderConfigAccount = + getAccountParsingAndAssertingFunction(Config); diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/cache.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/cache.ts new file mode 100644 index 000000000..23f74050a --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/cache.ts @@ -0,0 +1,34 @@ +import dexterity from '@hxronetwork/dexterity-ts'; +import { toHxroPrintTradeProviderConfig } from './models'; +import { toHxroPrintTradeProviderConfigAccount } from './accounts'; +import { Convergence } from '@/Convergence'; +import { CvgWallet, useCache } from '@/utils'; + +export const configCache = useCache( + async (cvg: Convergence, commitment = 'confirmed') => { + const configAddress = cvg.hxro().pdas().config(); + const account = await cvg.rpc().getAccount(configAddress, commitment); + const configAccount = toHxroPrintTradeProviderConfigAccount(account); + + return toHxroPrintTradeProviderConfig(configAccount); + } +); + +export const hxroManifestCache = useCache(async (cvg: Convergence) => { + // dexterity.getManifest adds a lot of clutter to logs, so we disable console.debug for this call + // TODO: remove this workaround when dexterity library is updated + const { debug } = console; + console.debug = () => {}; + let manifest: any; // dexterity doesn't export a type for a manifest + try { + manifest = await dexterity.getManifest( + cvg.connection.rpcEndpoint, + true, + new CvgWallet(cvg) + ); + } finally { + console.debug = debug; + } + + return manifest; +}); diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/client.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/client.ts new file mode 100644 index 000000000..2b2605277 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/client.ts @@ -0,0 +1,97 @@ +import { + FetchHxroPrintTradeProviderConfigInput, + FetchHxroPrintTradeProviderConfigOutput, + FetchHxroProductsInput, + FetchHxroProductsOutput, + InitializeHxroConfigInput, + InitializeHxroConfigOutput, + InitializeOperatorTraderRiskGroupInput, + InitializeOperatorTraderRiskGroupOutput, + ModifyHxroConfigInput, + ModifyHxroConfigOutput, + fetchHxroPrintTradeProviderConfigOperation, + fetchHxroProductsOperation, + initializeHxroConfigOperation, + initializeOperatorTraderRiskGroupOperation, + fetchUnusedCollateralLockRecordsOperation, + FetchUnusedCollateralLockRecordsInput, + FetchUnusedCollateralLockRecordsOutput, + unlockHxroCollateralByRecordOperation, + UnlockHxroCollateralByRecordInput, + UnlockHxroCollateralByRecordOutput, + modifyHxroConfigOperation, +} from './operations'; +import { HxroPdasClient } from './pdas'; +import { OperationOptions } from '@/types'; +import { Convergence } from '@/Convergence'; + +export class HxroClient { + constructor(protected readonly cvg: Convergence) {} + + pdas() { + return new HxroPdasClient(this.cvg); + } + + fetchConfig( + input?: FetchHxroPrintTradeProviderConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(fetchHxroPrintTradeProviderConfigOperation(input), options); + } + + fetchProducts( + input?: FetchHxroProductsInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(fetchHxroProductsOperation(input), options); + } + + initializeConfig( + input: InitializeHxroConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(initializeHxroConfigOperation(input), options); + } + + modifyConfig( + input: ModifyHxroConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(modifyHxroConfigOperation(input), options); + } + + initializeOperatorTraderRiskGroup( + input: InitializeOperatorTraderRiskGroupInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(initializeOperatorTraderRiskGroupOperation(input), options); + } + + fetchUnusedCollateralLockRecords( + input?: FetchUnusedCollateralLockRecordsInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(fetchUnusedCollateralLockRecordsOperation(input), options); + } + + unlockCollateralByRecord( + input: UnlockHxroCollateralByRecordInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(unlockHxroCollateralByRecordOperation(input), options); + } +} diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/constants.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/constants.ts new file mode 100644 index 000000000..c49612ebb --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/constants.ts @@ -0,0 +1,2 @@ +export const HXRO_QUOTE_DECIMALS = 9; +export const HXRO_LEG_DECIMALS = 9; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/dex.json b/packages/js/src/plugins/hxroPrintTradeProviderModule/dex.json new file mode 100644 index 000000000..e50bf8d58 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/dex.json @@ -0,0 +1,4605 @@ +{ + "version": "0.1.0", + "name": "dex", + "constants": [ + { + "name": "NAME_LEN", + "type": "u64", + "value": "16" + }, + { + "name": "MAX_OUTRIGHTS", + "type": "u64", + "value": "128" + }, + { + "name": "MAX_PRODUCTS", + "type": "u64", + "value": "256" + }, + { + "name": "HEALTH_BUFFER_LEN", + "type": "u64", + "value": "32" + }, + { + "name": "MAX_TRADER_POSITIONS", + "type": "u64", + "value": "16" + }, + { + "name": "MAX_OPEN_ORDERS_PER_POSITION", + "type": "u64", + "value": "256" + }, + { + "name": "MAX_OPEN_ORDERS", + "type": "u64", + "value": "1024" + }, + { + "name": "ANCHOR_DISCRIMINANT_LEN", + "type": "u64", + "value": "8" + }, + { + "name": "SENTINEL", + "type": "u64", + "value": "0" + }, + { + "name": "CALLBACK_INFO_LEN", + "type": "u64", + "value": "std :: mem :: size_of :: < CallBackInfo > () as u64" + }, + { + "name": "CALLBACK_ID_LEN", + "type": "u64", + "value": "32" + }, + { + "name": "MAX_COMBOS", + "type": "u64", + "value": "128" + }, + { + "name": "MAX_LEGS", + "type": "u64", + "value": "4" + }, + { + "name": "SLOTS_1_MIN", + "type": "u64", + "value": "150" + }, + { + "name": "SLOTS_5_MIN", + "type": "u64", + "value": "750" + }, + { + "name": "SLOTS_15_MIN", + "type": "u64", + "value": "2250" + }, + { + "name": "SLOTS_60_MIN", + "type": "u64", + "value": "9000" + } + ], + "instructions": [ + { + "name": "initializeMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultMint", + "isMut": false, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "sysvarRent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeMarketProductGroupParams" + } + } + ] + }, + { + "name": "updateMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateMarketProductGroupParams" + } + } + ] + }, + { + "name": "setAddressLookupTable", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "addressLookupTable", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeMarketProduct", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeMarketProductParams" + } + } + ] + }, + { + "name": "changeOrderbook", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "oldOrderbook", + "isMut": false, + "isSigner": false + }, + { + "name": "oldEventQueue", + "isMut": false, + "isSigner": false + }, + { + "name": "oldBids", + "isMut": false, + "isSigner": false + }, + { + "name": "oldAsks", + "isMut": false, + "isSigner": false + }, + { + "name": "newOrderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "deactivateMarketProduct", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "removeMarketProduct", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "removeMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "lockCollateral", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "feeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskStateAcct", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LockCollateralParams" + } + } + ] + }, + { + "name": "unlockCollateral", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "feeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskStateAcct", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LockCollateralParams" + } + } + ] + }, + { + "name": "initializePrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "operatorOwner", + "isMut": false, + "isSigner": true + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializePrintTradeParams" + } + } + ] + }, + { + "name": "initializePrintTradeExecutionOutput", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "executionOutput", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "signPrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": true, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": true, + "isSigner": false + }, + { + "name": "operator", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "creatorTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "SignPrintTradeParams" + } + } + ] + }, + { + "name": "executePrintTrade", + "accounts": [ + { + "name": "op", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": true, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": true, + "isSigner": false + }, + { + "name": "operator", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "creatorTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + }, + { + "name": "executionOutput", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "cancelPrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "closePrintTrade", + "accounts": [ + { + "name": "op", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorWallet", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeTraderRiskGroup", + "accounts": [ + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": true + }, + { + "name": "traderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "closeTraderRiskGroup", + "accounts": [ + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "newOrder", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "traderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "referrerTrg", + "isMut": true, + "isSigner": false, + "docs": [ + "referrer_trg receives a programmatic percentage of taker fees", + "sdks route this back to the user's trg", + "frontends will want to route this to their own trg" + ] + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "NewOrderParams" + } + } + ] + }, + { + "name": "clearOpenOrders", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ClearOpenOrdersParams" + } + } + ] + }, + { + "name": "reinitializeTraderPositions", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setNumRiskStateAccounts", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "SetNumRiskStateAccountsParams" + } + } + ] + }, + { + "name": "updateVarianceCache", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "consumeOrderbookEvents", + "accounts": [ + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardTarget", + "isMut": true, + "isSigner": true + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ConsumeOrderbookEventsParams" + } + } + ] + }, + { + "name": "cancelOrder", + "accounts": [ + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CancelOrderParams" + } + } + ] + }, + { + "name": "depositFunds", + "accounts": [ + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "capitalLimits", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "DepositFundsParams" + } + } + ] + }, + { + "name": "withdrawFunds", + "accounts": [ + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimits", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "WithdrawFundsParams" + } + } + ] + }, + { + "name": "updateProductFunding", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateProductFundingParams" + } + } + ] + }, + { + "name": "updateProductMarkPriceConfig", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateProductMarkPriceConfigParams" + } + } + ] + }, + { + "name": "transferFullPosition", + "accounts": [ + { + "name": "liquidator", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidateeRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidateeRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeCombo", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeComboParams" + } + } + ] + }, + { + "name": "updateTraderFunding", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "clearExpiredOrderbook", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ClearExpiredOrderbookParams" + } + } + ] + }, + { + "name": "popEvents", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PopEventsParams" + } + } + ] + }, + { + "name": "sweepFees", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollectorTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "stakingFeeCollectorTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "chooseSuccessor", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimAuthority", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "setupCapitalLimits", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimitsState", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateCapitalLimits", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimitsState", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CapitalLimitsParams" + } + } + ] + }, + { + "name": "updateTraderRiskGroup", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderFeeStateAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateTraderRiskGroupOwner", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "disableKillswitch", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "enableKillswitch", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "CapitalLimits", + "type": { + "kind": "struct", + "fields": [ + { + "name": "depositLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "withdrawalLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "MarketProductGroup", + "docs": [ + "The highest level organizational unit of the Dex.", + "Market product groups exist independently of each other.", + "i.e. each trader, product etc, corresponds to exactly one market product group." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "successor", + "type": "publicKey" + }, + { + "name": "vaultMint", + "type": "publicKey" + }, + { + "name": "collectedFees", + "type": { + "defined": "Fractional" + } + }, + { + "name": "feeCollector", + "type": "publicKey" + }, + { + "name": "decimals", + "type": "u64" + }, + { + "name": "riskEngineProgramId", + "type": "publicKey" + }, + { + "name": "feeModelProgramId", + "type": "publicKey" + }, + { + "name": "feeModelConfigurationAcct", + "type": "publicKey" + }, + { + "name": "riskModelConfigurationAcct", + "type": "publicKey" + }, + { + "name": "activeFlagsProducts", + "type": { + "defined": "Bitset" + } + }, + { + "name": "ewmaWindows", + "type": { + "array": [ + "u64", + 4 + ] + } + }, + { + "name": "marketProducts", + "type": { + "defined": "ProductArray" + } + }, + { + "name": "vaultBump", + "type": "u16" + }, + { + "name": "riskAndFeeBump", + "type": "u16" + }, + { + "name": "findFeesDiscriminantLen", + "type": "u16" + }, + { + "name": "validateAccountDiscriminantLen", + "type": "u16" + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountHealthDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountLiquidationDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxMakerFeeBps", + "type": "i16" + }, + { + "name": "minMakerFeeBps", + "type": "i16" + }, + { + "name": "maxTakerFeeBps", + "type": "i16" + }, + { + "name": "minTakerFeeBps", + "type": "i16" + }, + { + "name": "feeOutputRegister", + "type": "publicKey" + }, + { + "name": "riskOutputRegister", + "type": "publicKey" + }, + { + "name": "sequenceNumber", + "type": "u128" + }, + { + "name": "stakingFeeCollector", + "type": "publicKey" + }, + { + "name": "isKilled", + "type": "bool" + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "addressLookupTable", + "type": "publicKey" + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "ProductArray", + "type": { + "kind": "struct", + "fields": [ + { + "name": "array", + "type": { + "array": [ + { + "defined": "Product" + }, + 256 + ] + } + } + ] + } + }, + { + "name": "PrintTradeProduct", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTrade", + "type": { + "kind": "struct", + "fields": [ + { + "name": "isInitialized", + "type": "bool" + }, + { + "name": "creator", + "type": "publicKey" + }, + { + "name": "counterparty", + "type": "publicKey" + }, + { + "name": "seed", + "type": "publicKey" + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "numProducts", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operator", + "type": "publicKey" + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "isSigned", + "type": "bool" + }, + { + "name": "isCancelled", + "type": { + "defined": "CancelStatus" + } + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "RiskOutputRegister", + "type": { + "kind": "struct", + "fields": [ + { + "name": "riskEngineOutput", + "type": { + "defined": "HealthResult" + } + } + ] + } + }, + { + "name": "TraderRiskGroup", + "docs": [ + "State account corresponding to a trader on a given market product group" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "activeProducts", + "type": { + "array": [ + "u8", + 128 + ] + } + }, + { + "name": "totalDeposited", + "type": { + "defined": "Fractional" + } + }, + { + "name": "totalWithdrawn", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cashBalance", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingCashBalance", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingFees", + "type": { + "defined": "Fractional" + } + }, + { + "name": "validUntil", + "type": "u64" + }, + { + "name": "makerFeeBps", + "type": "i32" + }, + { + "name": "takerFeeBps", + "type": "i32" + }, + { + "name": "traderPositions", + "type": { + "array": [ + { + "defined": "TraderPosition" + }, + 16 + ] + } + }, + { + "name": "riskStateAccount", + "type": "publicKey" + }, + { + "name": "feeStateAccount", + "type": "publicKey" + }, + { + "name": "clientOrderId", + "type": "u128" + }, + { + "name": "openOrders", + "type": { + "defined": "OpenOrders" + } + }, + { + "name": "lockedCollateral", + "type": { + "array": [ + { + "defined": "LockedCollateral" + }, + 16 + ] + } + }, + { + "name": "notionalMakerVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "notionalTakerVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "referredTakersNotionalVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "referralFees", + "docs": [ + "referral_fees is not necessarily REFERRER_FEES_PROPORTION * referred_takers_notional_volume,", + "because combo volume has only collects 1/8th the fees as outright volume" + ], + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTradeExecutionOutput", + "type": { + "kind": "struct", + "fields": [ + { + "name": "result", + "type": { + "defined": "PrintTradeExecutionResult" + } + } + ] + } + }, + { + "name": "CapitalLimitsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "depositLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "withdrawalLimit", + "type": { + "defined": "Fractional" + } + } + ] + } + } + ], + "types": [ + { + "name": "LockedCollateralProductIndex", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTradeProductIndex", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "ProductArray", + "type": { + "kind": "struct", + "fields": [ + { + "name": "array", + "type": { + "array": [ + { + "defined": "Product" + }, + 256 + ] + } + } + ] + } + }, + { + "name": "Side", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Bid" + }, + { + "name": "Ask" + } + ] + } + }, + { + "name": "Params", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "CallBackInfo", + "docs": [ + "Buffer attached to aaob events to tie owner to events" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "userAccount", + "type": "publicKey" + }, + { + "name": "openOrdersIdx", + "type": "u64" + }, + { + "name": "orderNonce", + "type": "u128" + }, + { + "name": "clientOrderId", + "type": "u64" + } + ] + } + }, + { + "name": "TraderFees", + "type": { + "kind": "struct", + "fields": [ + { + "name": "validUntil", + "type": "i64" + }, + { + "name": "makerFeeBps", + "type": "i32" + }, + { + "name": "takerFeeBps", + "type": "i32" + } + ] + } + }, + { + "name": "TraderFeeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "isAggressor", + "type": "bool" + }, + { + "name": "matchedQuoteQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "matchedBaseQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "product", + "type": "publicKey" + } + ] + } + }, + { + "name": "PriceEwma", + "type": { + "kind": "struct", + "fields": [ + { + "name": "ewmaBid", + "type": { + "array": [ + { + "defined": "Fractional" + }, + 4 + ] + } + }, + { + "name": "ewmaAsk", + "type": { + "array": [ + { + "defined": "Fractional" + }, + 4 + ] + } + }, + { + "name": "bid", + "type": { + "defined": "Fractional" + } + }, + { + "name": "ask", + "type": { + "defined": "Fractional" + } + }, + { + "name": "slot", + "type": "u64" + }, + { + "name": "prevBid", + "type": { + "defined": "Fractional" + } + }, + { + "name": "prevAsk", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "OpenOrdersMetadata", + "type": { + "kind": "struct", + "fields": [ + { + "name": "askQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "bidQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "headIndex", + "type": "u64" + }, + { + "name": "numOpenOrders", + "type": "u64" + } + ] + } + }, + { + "name": "OpenOrders", + "type": { + "kind": "struct", + "fields": [ + { + "name": "freeListHead", + "type": "u64" + }, + { + "name": "totalOpenOrders", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "OpenOrdersMetadata" + }, + 256 + ] + } + }, + { + "name": "orders", + "type": { + "array": [ + { + "defined": "OpenOrdersNode" + }, + 1024 + ] + } + } + ] + } + }, + { + "name": "OpenOrdersNode", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u128" + }, + { + "name": "qty", + "type": "u64" + }, + { + "name": "clientId", + "type": "u64" + }, + { + "name": "prev", + "type": "u64" + }, + { + "name": "next", + "type": "u64" + } + ] + } + }, + { + "name": "Outright", + "docs": [ + "A market product corresponding to one underlying asset" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "metadata", + "type": { + "defined": "ProductMetadata" + } + }, + { + "name": "numRiskStateAccounts", + "docs": [ + "num_risk_state_accounts is the number of risk state accounts that have an untidied entry related to this product.", + "The DEX assumes that the attached risk engine will tidy (this likely means \"remove\")", + "risk entries related to this product during the first risk check after removing a TraderPosition." + ], + "type": "u64" + }, + { + "name": "productStatus", + "type": { + "defined": "ProductStatus" + } + }, + { + "name": "dust", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cumFundingPerShare", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cumSocialLossPerShare", + "type": { + "defined": "Fractional" + } + }, + { + "name": "openLongInterest", + "type": { + "defined": "Fractional" + } + }, + { + "name": "openShortInterest", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceQualifyingCumValue", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceMaxQualifyingWidth", + "type": { + "defined": "Fractional" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u64", + 10 + ] + } + } + ] + } + }, + { + "name": "ProductMetadata", + "docs": [ + "Shared fields between Outright and Combo products" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u64" + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "orderbook", + "type": "publicKey" + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + }, + { + "name": "notionalTradedVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "prices", + "type": { + "defined": "PriceEwma" + } + } + ] + } + }, + { + "name": "Combo", + "docs": [ + "A market product with multiple legs that are each outrights" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "metadata", + "type": { + "defined": "ProductMetadata" + } + }, + { + "name": "numLegs", + "type": "u64" + }, + { + "name": "legsArray", + "type": { + "array": [ + { + "defined": "Leg" + }, + 4 + ] + } + } + ] + } + }, + { + "name": "Leg", + "docs": [ + "One part of a combo. Each leg corresponds to an outright with the ratio determining", + "relative weighting" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "ratio", + "type": "i64" + } + ] + } + }, + { + "name": "HealthInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "health", + "type": { + "defined": "HealthStatus" + } + }, + { + "name": "action", + "type": { + "defined": "ActionStatus" + } + } + ] + } + }, + { + "name": "LiquidationInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "health", + "type": { + "defined": "HealthStatus" + } + }, + { + "name": "action", + "type": { + "defined": "ActionStatus" + } + }, + { + "name": "totalSocialLoss", + "type": { + "defined": "Fractional" + } + }, + { + "name": "liquidationPrice", + "type": { + "defined": "Fractional" + } + }, + { + "name": "socialLosses", + "type": { + "array": [ + { + "defined": "SocialLoss" + }, + 16 + ] + } + } + ] + } + }, + { + "name": "SocialLoss", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "amount", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "OrderInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "totalOrderQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "matchedOrderQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "orderSide", + "type": { + "defined": "Side" + } + }, + { + "name": "orderPrice", + "type": { + "defined": "Fractional" + } + }, + { + "name": "isCombo", + "type": "bool" + }, + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "operationType", + "type": { + "defined": "OperationType" + } + }, + { + "name": "oldAskQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "oldBidQtyInBook", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "TraderPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "position", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingPosition", + "type": { + "defined": "Fractional" + } + }, + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "lastCumFundingSnapshot", + "type": { + "defined": "Fractional" + } + }, + { + "name": "lastSocialLossSnapshot", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "LockedCollateral", + "docs": [ + "there is one LockedCollateral for each product; the array is in one-to-one mapping with trader_positions" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "askQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "bidQty", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "Bitset", + "type": { + "kind": "struct", + "fields": [ + { + "name": "inner", + "type": { + "array": [ + "u128", + 2 + ] + } + } + ] + } + }, + { + "name": "Fractional", + "docs": [ + "Fractional Operations" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "m", + "type": "i64" + }, + { + "name": "exp", + "type": "u64" + } + ] + } + }, + { + "name": "InitializeMarketProductGroupParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "validateAccountDiscriminantLen", + "type": "u64" + }, + { + "name": "findFeesDiscriminantLen", + "type": "u64" + }, + { + "name": "validateAccountHealthDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountLiquidationDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxMakerFeeBps", + "type": "i16" + }, + { + "name": "minMakerFeeBps", + "type": "i16" + }, + { + "name": "maxTakerFeeBps", + "type": "i16" + }, + { + "name": "minTakerFeeBps", + "type": "i16" + } + ] + } + }, + { + "name": "UpdateMarketProductGroupParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "findFeesDiscriminantLen", + "type": "u16" + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "InitializePrintTradeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "LockCollateralParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "LockedCollateralProductIndex" + }, + 6 + ] + } + } + ] + } + }, + { + "name": "SignPrintTradeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "InitializeMarketProductParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "NewOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "side", + "docs": [ + "The order's side (Bid or Ask)" + ], + "type": { + "defined": "Side" + } + }, + { + "name": "maxBaseQty", + "docs": [ + "The max quantity of base token to match and post" + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "orderType", + "docs": [ + "The order type (supported types include Limit, FOK, IOC and PostOnly)" + ], + "type": { + "defined": "OrderType" + } + }, + { + "name": "matchLimit", + "docs": [ + "The maximum number of orders to be matched against.", + "Setting this number too high can sometimes lead to excessive resource consumption which can cause a failure." + ], + "type": "u64" + }, + { + "name": "limitPrice", + "docs": [ + "The order's limit price in ticks" + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "referrerFeeBps", + "docs": [ + "In addition to taker fees; routed to referrer_trg; can be zero", + "Should be used like this: 3bps -> use the value Fractional{ m: 3, exp: 4 }", + "Min: 0; Max: 100bps." + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "clientOrderId", + "docs": [ + "Order id that can be specified by client. Can be arbitrary u64. Defaults to the value 0." + ], + "type": "u64" + } + ] + } + }, + { + "name": "ClearOpenOrdersParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + } + ] + } + }, + { + "name": "SetNumRiskStateAccountsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numRiskStateAccounts", + "type": "u64" + } + ] + } + }, + { + "name": "ConsumeOrderbookEventsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxIterations", + "docs": [ + "The maximum number of events to consume" + ], + "type": "u64" + } + ] + } + }, + { + "name": "CancelOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "orderId", + "docs": [ + "The order_id of the order to cancel. Redundancy is used here to avoid having to iterate over all", + "open orders on chain. If order_id == 0, then client_order_id is used." + ], + "type": "u128" + }, + { + "name": "noErr", + "docs": [ + "do not fail when order is not found" + ], + "type": "bool" + }, + { + "name": "clientOrderId", + "docs": [ + "The client_order_id of the order to cancel. Used when order_id == 0." + ], + "type": "u64" + } + ] + } + }, + { + "name": "DepositFundsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "WithdrawFundsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "UpdateProductFundingParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "Fractional" + } + }, + { + "name": "newProductStatus", + "type": { + "defined": "ProductStatus" + } + } + ] + } + }, + { + "name": "UpdateProductMarkPriceConfigParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "markPriceQualifyingCumValue", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceMaxQualifyingWidth", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "InitializeComboParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "ratios", + "type": { + "vec": "i8" + } + } + ] + } + }, + { + "name": "PopEventsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numEventsToPop", + "type": "u64" + } + ] + } + }, + { + "name": "ClearExpiredOrderbookParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numOrdersToCancel", + "type": "u8" + } + ] + } + }, + { + "name": "DomainOrProgramError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "DexErr", + "fields": [ + { + "defined": "DexError" + } + ] + }, + { + "name": "UtilErr", + "fields": [ + { + "defined": "UtilError" + } + ] + }, + { + "name": "ProgramErr", + "fields": [ + { + "name": "msg", + "type": "string" + } + ] + }, + { + "name": "Other", + "fields": [ + { + "name": "code", + "type": "u32" + }, + { + "name": "msg", + "type": "string" + } + ] + } + ] + } + }, + { + "name": "UtilError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AccountAlreadyInitialized" + }, + { + "name": "AccountUninitialized" + }, + { + "name": "DuplicateProductKey" + }, + { + "name": "PublicKeyMismatch" + }, + { + "name": "AssertionError" + }, + { + "name": "InvalidMintAuthority" + }, + { + "name": "IncorrectOwner" + }, + { + "name": "PublicKeysShouldBeUnique" + }, + { + "name": "NotRentExempt" + }, + { + "name": "NumericalOverflow" + }, + { + "name": "RoundError" + }, + { + "name": "DivisionbyZero" + }, + { + "name": "InvalidReturnValue" + }, + { + "name": "SqrtRootError" + }, + { + "name": "ZeroPriceError" + }, + { + "name": "ZeroQuantityError" + }, + { + "name": "SerializeError" + }, + { + "name": "DeserializeError" + }, + { + "name": "InvalidBitsetIndex" + }, + { + "name": "PushToFullBitvec" + }, + { + "name": "U8MaxNotAllowedInBitvec" + } + ] + } + }, + { + "name": "DexError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ContractIsExpired" + }, + { + "name": "ContractIsNotExpired" + }, + { + "name": "InvalidSystemProgramAccount" + }, + { + "name": "InvalidAobProgramAccount" + }, + { + "name": "InvalidStateAccountOwner" + }, + { + "name": "InvalidOrderIndex" + }, + { + "name": "UserAccountFull" + }, + { + "name": "TransactionAborted" + }, + { + "name": "MissingUserAccount" + }, + { + "name": "OrderNotFound" + }, + { + "name": "NoOp" + }, + { + "name": "OutofFunds" + }, + { + "name": "UserAccountStillActive" + }, + { + "name": "MarketStillActive" + }, + { + "name": "InvalidMarketSignerAccount" + }, + { + "name": "InvalidOrderbookAccount" + }, + { + "name": "InvalidMarketAdminAccount" + }, + { + "name": "InvalidBaseVaultAccount" + }, + { + "name": "InvalidQuoteVaultAccount" + }, + { + "name": "FullMarketProductGroup" + }, + { + "name": "MissingMarketProduct" + }, + { + "name": "InvalidWithdrawalAmount" + }, + { + "name": "InvalidTakerTrader" + }, + { + "name": "FundsError" + }, + { + "name": "InactiveProductError" + }, + { + "name": "TooManyOpenOrdersError" + }, + { + "name": "NoMoreOpenOrdersError" + }, + { + "name": "NonZeroPriceTickExponentError" + }, + { + "name": "DuplicateProductNameError" + }, + { + "name": "InvalidRiskResponseError" + }, + { + "name": "InvalidAccountHealthError" + }, + { + "name": "OrderbookIsEmptyError" + }, + { + "name": "CombosNotRemoved" + }, + { + "name": "AccountNotLiquidable" + }, + { + "name": "FundingPrecisionError" + }, + { + "name": "ProductDecimalPrecisionError" + }, + { + "name": "ProductNotOutright" + }, + { + "name": "ProductNotCombo" + }, + { + "name": "InvalidSocialLossCalculation" + }, + { + "name": "ProductIndexMismatch" + }, + { + "name": "InvalidOrderID" + }, + { + "name": "InvalidBytesForZeroCopyDeserialization" + }, + { + "name": "IncorrectPrintTradeSize" + }, + { + "name": "IncorrectPrintTradePrice" + }, + { + "name": "IncorrectPrintTradeSide" + }, + { + "name": "IncorrectPrintTradeOperatorCreatorFees" + }, + { + "name": "IncorrectPrintTradeOperatorCounterpartyFees" + }, + { + "name": "InvalidPrintTradeOperatorFees" + }, + { + "name": "DepositLimitExceeded" + }, + { + "name": "WithdrawLimitExceeded" + }, + { + "name": "NegativeDepositLimit" + }, + { + "name": "NegativeWithdrawLimit" + }, + { + "name": "DepositDeniedInsufficientBalanceOnWhitelistAtaToken" + }, + { + "name": "DepositDeclinedUnfrozenWhitelistAtaToken" + }, + { + "name": "DepositDeclinedNonExistentWhitelistAtaTokenOnTraderRiskGroup" + }, + { + "name": "InvalidProductStatusInUpdateFunding" + }, + { + "name": "ContractIsNotExpiring" + }, + { + "name": "ContractHasNonZeroOpenInterest" + }, + { + "name": "ContractHasNonZeroOpenInterestOrRiskStateAccounts" + }, + { + "name": "ContractIsActive" + }, + { + "name": "FailedToGetOrderQuantity" + }, + { + "name": "SelfTradeBehaviorDecrementTakeIsDisallowed" + }, + { + "name": "PriceBandViolation" + }, + { + "name": "UnexpectedImbalancedOpenInterest" + }, + { + "name": "MaximumOpenInterestExceeded" + }, + { + "name": "MarketProductGroupKillswitchIsOn" + }, + { + "name": "InvalidFutureExpiry" + }, + { + "name": "MaxReferrerFeeBpsExceeded" + }, + { + "name": "PrintTradeOperatorDidNotSign" + }, + { + "name": "PrintTradeInvalidProductsLength" + }, + { + "name": "ContractIsNotActive" + }, + { + "name": "PrintTradeInvalidNumProducts" + }, + { + "name": "PrintTradeProductMismatch" + }, + { + "name": "InsufficientLockedCollateral" + }, + { + "name": "OracleNotWhitelisted" + } + ] + } + }, + { + "name": "AccountTag", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "MarketProductGroup" + }, + { + "name": "TraderRiskGroup" + }, + { + "name": "TraderPosition" + }, + { + "name": "MarketProductGroupWithCombos" + }, + { + "name": "ComboGroup" + }, + { + "name": "Combo" + }, + { + "name": "RiskProfile" + }, + { + "name": "LockedCollateral" + } + ] + } + }, + { + "name": "ProductStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "Initialized" + }, + { + "name": "Expired" + }, + { + "name": "Expiring" + } + ] + } + }, + { + "name": "OrderType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Limit" + }, + { + "name": "ImmediateOrCancel" + }, + { + "name": "FillOrKill" + }, + { + "name": "PostOnly" + } + ] + } + }, + { + "name": "CancelStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Active" + }, + { + "name": "CreatorCancelled" + }, + { + "name": "CounterpartyCancelled" + } + ] + } + }, + { + "name": "Product", + "docs": [ + "Unify Outright and Combo" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Outright", + "fields": [ + { + "name": "outright", + "type": { + "defined": "Outright" + } + } + ] + }, + { + "name": "Combo", + "fields": [ + { + "name": "combo", + "type": { + "defined": "Combo" + } + } + ] + } + ] + } + }, + { + "name": "OperationType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "NewOrder" + }, + { + "name": "CancelOrder" + }, + { + "name": "CheckHealth" + }, + { + "name": "PositionTransfer" + }, + { + "name": "ConsumeEvents" + }, + { + "name": "CheckWithdrawalHealth" + }, + { + "name": "LockCollateral" + }, + { + "name": "SignPrinTrade" + } + ] + } + }, + { + "name": "HealthResult", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Health", + "fields": [ + { + "name": "health_info", + "type": { + "defined": "HealthInfo" + } + } + ] + }, + { + "name": "Liquidation", + "fields": [ + { + "name": "liquidation_info", + "type": { + "defined": "LiquidationInfo" + } + } + ] + } + ] + } + }, + { + "name": "HealthStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Healthy" + }, + { + "name": "Unhealthy" + }, + { + "name": "Liquidatable" + }, + { + "name": "NotLiquidatable" + } + ] + } + }, + { + "name": "ActionStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Approved" + }, + { + "name": "NotApproved" + } + ] + } + }, + { + "name": "PrintTradeExecutionResult", + "type": { + "kind": "enum", + "variants": [ + { + "name": "CounterpartyHasntSigned" + }, + { + "name": "CreatorCancelled" + }, + { + "name": "CounterpartyCancelled" + }, + { + "name": "CreatorNotEnoughLockedCollateral" + }, + { + "name": "CounterpartyNotEnoughLockedCollateral" + }, + { + "name": "Success" + } + ] + } + } + ], + "events": [ + { + "name": "DexOrderSummary", + "fields": [ + { + "name": "postedOrderId", + "type": { + "option": "u128" + }, + "index": false + }, + { + "name": "totalBaseQty", + "type": "u64", + "index": false + }, + { + "name": "totalQuoteQty", + "type": "u64", + "index": false + }, + { + "name": "totalBaseQtyPosted", + "type": "u64", + "index": false + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/gpa.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/gpa.ts new file mode 100644 index 000000000..4b9b9cb0b --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/gpa.ts @@ -0,0 +1,28 @@ +import { PublicKey } from '@solana/web3.js'; +import { + PROGRAM_ID, + lockedCollateralRecordDiscriminator, +} from '@convergence-rfq/hxro-print-trade-provider'; + +import { Convergence } from '../../Convergence'; +import { GpaBuilder } from '../../utils'; + +const USER = 8; +const RESPONSE = USER + 32; +const TRG = RESPONSE + 32; +const IS_IN_USE = TRG + 32; + +export class LockCollateralRecordGpaBuilder extends GpaBuilder { + constructor(convergence: Convergence, programId?: PublicKey) { + super(convergence, programId ?? PROGRAM_ID); + this.where(0, Buffer.from(lockedCollateralRecordDiscriminator)); + } + + whereUser(user: PublicKey) { + return this.where(USER, user); + } + + whereInUse(isInUse: boolean) { + return this.where(IS_IN_USE, isInUse ? 1 : 0); + } +} diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/helpers.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/helpers.ts new file mode 100644 index 000000000..1325dbf20 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/helpers.ts @@ -0,0 +1,36 @@ +import BigNumber from 'bignumber.js'; +import BN from 'bn.js'; +import { HXRO_LEG_DECIMALS } from './constants'; +import { Convergence } from '@/Convergence'; +import { PublicKey } from '@/types'; + +export const fetchValidHxroMpg = async (cvg: Convergence, manifest: any) => { + const { validMpg } = await cvg.hxro().fetchConfig(); + + const mpg = await manifest.getMPG(validMpg); + return { pubkey: validMpg, ...mpg }; +}; + +export const numberToHxroFractional = (value: number, negate?: boolean) => { + let withDecimals = new BigNumber(value).times( + new BigNumber(10).pow(HXRO_LEG_DECIMALS) + ); + + if (negate) { + withDecimals = withDecimals.negated(); + } + + return { m: new BN(withDecimals.toString()), exp: new BN(HXRO_LEG_DECIMALS) }; +}; + +export const getFirstHxroExecutionOutput = async ( + cvg: Convergence, + dexProgramId: PublicKey +) => { + const [{ pubkey }] = await cvg.connection.getProgramAccounts(dexProgramId, { + dataSlice: { length: 1, offset: 0 }, + filters: [{ memcmp: { offset: 0, bytes: 'EdEf3SczfYR' } }], + }); + + return pubkey; +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/index.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/index.ts new file mode 100644 index 000000000..10622f2d4 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/index.ts @@ -0,0 +1,9 @@ +export * from './printTrade'; +export * from './constants'; +export * from './accounts'; +export * from './pdas'; +export * from './plugin'; +export * from './program'; +export * from './operations'; +export * from './models'; +export * from './types'; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/models/Config.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/models/Config.ts new file mode 100644 index 000000000..8ca823088 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/models/Config.ts @@ -0,0 +1,21 @@ +import { PublicKey } from '@solana/web3.js'; + +import { HxroPrintTradeProviderConfigAccount } from '../accounts'; + +export type HxroPrintTradeProviderConfig = { + /** A model identifier to distinguish models in the SDK. */ + readonly model: 'hxroPrintTradeProviderConfig'; + + readonly address: PublicKey; + + readonly validMpg: PublicKey; +}; + +/** @group Model Helpers */ +export const toHxroPrintTradeProviderConfig = ( + account: HxroPrintTradeProviderConfigAccount +): HxroPrintTradeProviderConfig => ({ + model: 'hxroPrintTradeProviderConfig', + address: account.publicKey, + validMpg: account.data.validMpg, +}); diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/models/index.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/models/index.ts new file mode 100644 index 000000000..bd37f302d --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/models/index.ts @@ -0,0 +1 @@ +export * from './Config'; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroPrintTradeProviderConfig.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroPrintTradeProviderConfig.ts new file mode 100644 index 000000000..d4dabf282 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroPrintTradeProviderConfig.ts @@ -0,0 +1,58 @@ +import { + Operation, + OperationHandler, + OperationScope, + useOperation, +} from '../../../types'; +import { Convergence } from '../../../Convergence'; +import { HxroPrintTradeProviderConfig } from '../models'; +import { configCache } from '../cache'; + +const Key = 'FetchHxroPrintTradeProviderConfig' as const; + +export const fetchHxroPrintTradeProviderConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type FetchHxroPrintTradeProviderConfigOperation = Operation< + typeof Key, + FetchHxroPrintTradeProviderConfigInput, + FetchHxroPrintTradeProviderConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type FetchHxroPrintTradeProviderConfigInput = {} | undefined; + +/** + * @group Operations + * @category Outputs + */ +export type FetchHxroPrintTradeProviderConfigOutput = + HxroPrintTradeProviderConfig; + +/** + * @group Operations + * @category Handlers + */ +export const fetchHxroPrintTradeProviderConfigOperationHandler: OperationHandler = + { + handle: async ( + _operation: FetchHxroPrintTradeProviderConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const { commitment } = scope; + + const config = await configCache.get(cvg, commitment); + + scope.throwIfCanceled(); + + return config; + }, + }; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroProducts.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroProducts.ts new file mode 100644 index 000000000..650bc5c67 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchHxroProducts.ts @@ -0,0 +1,199 @@ +import dexterity from '@hxronetwork/dexterity-ts'; +import BN from 'bn.js'; +import { OptionType } from '@convergence-rfq/risk-engine'; +import { HxroProductInfo } from '../types'; +import { fetchValidHxroMpg } from '../helpers'; +import { hxroManifestCache } from '../cache'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + PublicKey, + useOperation, +} from '@/types'; +import { BaseAsset } from '@/plugins/protocolModule'; + +const Key = 'FetchHxroProducts' as const; + +export const fetchHxroProductsOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type FetchHxroProductsOperation = Operation< + typeof Key, + FetchHxroProductsInput, + FetchHxroProductsOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type FetchHxroProductsInput = {} | undefined; + +/** + * @group Operations + * @category Outputs + */ +export type FetchHxroProductsOutput = HxroProductInfo[]; + +type BaseProductData = { + productIndex: number; + productName: string; + productAddress: PublicKey; +}; + +/** + * @group Operations + * @category Handlers + */ +export const fetchHxroProductsOperationHandler: OperationHandler = + { + handle: async ( + _operation: FetchHxroProductsOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const manifest = await hxroManifestCache.get(cvg); + const baseProductData = await parseBaseProductData(cvg, manifest); + scope.throwIfCanceled(); + + const baseAssets = await cvg.protocol().getBaseAssets(); + const productsData = await Promise.all( + baseProductData.map((baseData) => + expandProductData(manifest, baseAssets, baseData) + ) + ); + + scope.throwIfCanceled(); + + return productsData.filter((x): x is HxroProductInfo => x !== null); + }, + }; + +const parseBaseProductData = async ( + cvg: Convergence, + manifest: any +): Promise => { + const mpg = await fetchValidHxroMpg(cvg, manifest); + + return [...dexterity.Manifest.GetProductsOfMPG(mpg).values()] + .filter((productInfo) => productInfo.product?.outright !== undefined) + .map((productInfo) => { + const byteName: number[] = + productInfo.product.outright.outright.metadata.name; + const name = byteName.map((char) => String.fromCharCode(char)).join(''); + return { + productIndex: productInfo.index as number, + productName: name, + productAddress: productInfo.product.outright.outright.metadata + .productKey as PublicKey, + }; + }); +}; + +const expandProductData = async ( + manifest: any, + baseAssets: BaseAsset[], + baseData: BaseProductData +): Promise => { + const metadata = await manifest.getDerivativeMetadata( + baseData.productAddress + ); + const { + instrumentType: rawInstrumentType, + strike, + initializationTime, + fullFundingPeriod, + oracleType, + priceOracle, + } = metadata; + const strikePriceIsZero = strike.m.eq(new BN(0)); + const instrumentType = parseHxroInstrumentType(rawInstrumentType); + + const baseAsset = baseAssets.find( + (baseAsset) => + baseAsset.enabled && + baseAsset.pythOracle !== undefined && + oracleType.pyth !== undefined && + baseAsset.pythOracle.equals(priceOracle) + ); + + if (baseAsset === undefined) { + return null; + } + + const commonInResponse = { + ...baseData, + baseAssetIndex: baseAsset.index, + }; + + const isOption = + !strikePriceIsZero && + (instrumentType === 'expiring-call' || instrumentType === 'expiring-put'); + const isTermFuture = strikePriceIsZero && instrumentType === 'expiring-call'; + const isPerpFuture = instrumentType === 'recurring-call'; + const expirationTimestamp = + isOption || isTermFuture + ? initializationTime.add(fullFundingPeriod) + : undefined; + + // filter out expired products + if (expirationTimestamp !== undefined) { + const currentTimestamp = Date.now() / 1000; // convert to seconds + + if (expirationTimestamp <= currentTimestamp) { + return null; + } + } + + if (isOption) { + return { + ...commonInResponse, + instrumentType: 'option', + optionType: + instrumentType === 'expiring-call' ? OptionType.Call : OptionType.Put, + strikePrice: strike, + expirationTimestamp, + }; + } + if (isTermFuture) { + return { + ...commonInResponse, + instrumentType: 'term-future', + expirationTimestamp, + }; + } + if (isPerpFuture) { + return { + ...commonInResponse, + instrumentType: 'perp-future', + }; + } + + return null; +}; + +const parseHxroInstrumentType = (instrumentType: any) => { + if (instrumentType.expiringCall !== undefined) { + return 'expiring-call'; + } + + if (instrumentType.expiringPut !== undefined) { + return 'expiring-put'; + } + + if (instrumentType.recurringCall !== undefined) { + return 'recurring-call'; + } + + if (instrumentType.recurringPut !== undefined) { + return 'recurring-put'; + } + + throw new Error('Unrecognized Hxro instrument type!'); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchUnusedCollateralLockRecords.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchUnusedCollateralLockRecords.ts new file mode 100644 index 000000000..09a974503 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/fetchUnusedCollateralLockRecords.ts @@ -0,0 +1,74 @@ +import { + LockedCollateralRecord, + LockedCollateralRecordArgs, +} from '@convergence-rfq/hxro-print-trade-provider'; + +import { LockCollateralRecordGpaBuilder } from '../gpa'; +import { WithPubkey } from '../types'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + useOperation, +} from '@/types'; + +const Key = 'fetchUnusedCollateralLockRecords' as const; + +export const fetchUnusedCollateralLockRecordsOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type FetchUnusedCollateralLockRecordsOperation = Operation< + typeof Key, + FetchUnusedCollateralLockRecordsInput, + FetchUnusedCollateralLockRecordsOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type FetchUnusedCollateralLockRecordsInput = {} | undefined; + +/** + * @group Operations + * @category Outputs + */ +export type FetchUnusedCollateralLockRecordsOutput = + WithPubkey[]; + +/** + * @group Operations + * @category Handlers + */ +export const fetchUnusedCollateralLockRecordsOperationHandler: OperationHandler = + { + handle: async ( + _operation: FetchUnusedCollateralLockRecordsOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const { programs } = scope; + const hxroPrintTradeProviderProgram = cvg + .programs() + .getHxroPrintTradeProvider(programs); + const gpaBuilder = new LockCollateralRecordGpaBuilder( + cvg, + hxroPrintTradeProviderProgram.address + ); + + const unparsedAccounts = await gpaBuilder + .whereUser(cvg.identity().publicKey) + .whereInUse(false) + .get(); + + return unparsedAccounts.map((acc) => ({ + ...LockedCollateralRecord.deserialize(acc.data)[0], + publicKey: acc.publicKey, + })); + }, + }; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/index.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/index.ts new file mode 100644 index 000000000..6cff29ad4 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/index.ts @@ -0,0 +1,9 @@ +export * from './fetchHxroPrintTradeProviderConfig'; +export * from './fetchHxroProducts'; +export * from './initializeHxroConfig'; +export * from './modifyHxroConfig'; +export * from './initializeOperatorPrintTradeProvider'; +export * from './lockHxroCollateral'; +export * from './signHxroPrintTrade'; +export * from './fetchUnusedCollateralLockRecords'; +export * from './unlockHxroCollateralByRecord'; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeHxroConfig.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeHxroConfig.ts new file mode 100644 index 000000000..387036489 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeHxroConfig.ts @@ -0,0 +1,107 @@ +import { createInitializeConfigInstruction } from '@convergence-rfq/hxro-print-trade-provider'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + PublicKey, + makeConfirmOptionsFinalizedOnMainnet, + useOperation, +} from '@/types'; +import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; + +const Key = 'InitializeHxroConfig' as const; + +export const initializeHxroConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type InitializeHxroConfigOperation = Operation< + typeof Key, + InitializeHxroConfigInput, + InitializeHxroConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type InitializeHxroConfigInput = { + validMpg: PublicKey; + + authority?: PublicKey; +}; + +/** + * @group Operations + * @category Outputs + */ +export type InitializeHxroConfigOutput = SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const initializeHxroConfigOperationHandler: OperationHandler = + { + handle: async ( + operation: InitializeHxroConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const builder = await initializeHxroConfigBuilder( + cvg, + operation.input, + scope + ); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + cvg, + scope.confirmOptions + ); + const output = await builder.sendAndConfirm(cvg, confirmOptions); + scope.throwIfCanceled(); + return output.response; + }, + }; + +export const initializeHxroConfigBuilder = async ( + cvg: Convergence, + params: InitializeHxroConfigInput, + options: TransactionBuilderOptions = {} +): Promise> => { + const { authority = cvg.identity().publicKey, validMpg } = params; + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + + const hxroPrintTradeProviderProgram = cvg + .programs() + .getHxroPrintTradeProvider(); + const systemProgram = cvg.programs().getSystem(programs); + + const protocol = cvg.protocol().pdas().protocol(); + const config = cvg.hxro().pdas().config(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction: createInitializeConfigInstruction( + { + protocol, + authority, + config, + systemProgram: systemProgram.address, + }, + { + validMpg, + }, + hxroPrintTradeProviderProgram.address + ), + signers: [payer], + key: 'initializeHxroConfig', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeOperatorPrintTradeProvider.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeOperatorPrintTradeProvider.ts new file mode 100644 index 000000000..ef927cce1 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/initializeOperatorPrintTradeProvider.ts @@ -0,0 +1,165 @@ +import { createInitializeOperatorTraderRiskGroupInstruction } from '@convergence-rfq/hxro-print-trade-provider'; +import { Keypair, PublicKey, SystemProgram } from '@solana/web3.js'; +import dexterity from '@hxronetwork/dexterity-ts'; +import { fetchValidHxroMpg } from '../helpers'; +import { hxroManifestCache } from '../cache'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + makeConfirmOptionsFinalizedOnMainnet, + useOperation, +} from '@/types'; +import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; + +const Key = 'InitializeOperatorTraderRiskGroup' as const; + +export const initializeOperatorTraderRiskGroupOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type InitializeOperatorTraderRiskGroupOperation = Operation< + typeof Key, + InitializeOperatorTraderRiskGroupInput, + InitializeOperatorTraderRiskGroupOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type InitializeOperatorTraderRiskGroupInput = { + // Optional keypair which would be used as an account for trg + // A new account would be generated otherwise + trgAccount?: Keypair; + + // Optional keypair which would be used as an account for trg risk state + // A new account would be generated otherwise + riskStateAccount?: Keypair; + + // Allows overriding a hxro risk engine address compared to SDK + // This is used primarily in tests + hxroRiskEngineAddress?: PublicKey; +}; + +/** + * @group Operations + * @category Outputs + */ +export type InitializeOperatorTraderRiskGroupOutput = + SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const initializeOperatorTraderRiskGroupOperationHandler: OperationHandler = + { + handle: async ( + operation: InitializeOperatorTraderRiskGroupOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const builder = await initializeOperatorTraderRiskGroupBuilder( + cvg, + operation.input, + scope + ); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + cvg, + scope.confirmOptions + ); + const output = await builder.sendAndConfirm(cvg, confirmOptions); + scope.throwIfCanceled(); + return output.response; + }, + }; + +export const initializeOperatorTraderRiskGroupBuilder = async ( + cvg: Convergence, + params: InitializeOperatorTraderRiskGroupInput, + options: TransactionBuilderOptions = {} +): Promise> => { + const { + trgAccount = new Keypair(), + riskStateAccount = new Keypair(), + hxroRiskEngineAddress, + } = params; + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + + const manifest = await hxroManifestCache.get(cvg); + const hxroPrintTradeProviderProgram = cvg + .programs() + .getHxroPrintTradeProvider(); + const systemProgram = cvg.programs().getSystem(programs); + + const { dexProgram } = manifest.fields; + const { + pubkey: mpgAddress, + feeModelProgramId, + feeModelConfigurationAcct, + } = await fetchValidHxroMpg(cvg, manifest); + const [traderFeeStateAcct] = PublicKey.findProgramAddressSync( + [ + mpgAddress.toBuffer(), + trgAccount.publicKey.toBuffer(), + feeModelConfigurationAcct.toBuffer(), + ], + feeModelProgramId + ); + + const riskEngineProgram = + hxroRiskEngineAddress ?? manifest.fields.riskProgram.programId; + const createTrgInstruction = + await dexProgram.account.traderRiskGroup.createInstruction( + trgAccount, + 64336 // copied from hxro SDK TRG_SIZE variable + ); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction: createTrgInstruction, + signers: [payer, trgAccount], + key: 'createOperatorTraderRiskGroupAccount', + }) + .add({ + instruction: SystemProgram.transfer({ + fromPubkey: cvg.identity().publicKey, + toPubkey: cvg.hxro().pdas().operator(), + lamports: 1 * 10 ** 9, // 1 sol + }), + signers: [payer], + key: 'fundOperator', + }) + .add({ + instruction: createInitializeOperatorTraderRiskGroupInstruction( + { + authority: cvg.identity().publicKey, + protocol: cvg.protocol().pdas().protocol(), + config: cvg.hxro().pdas().config(), + marketProductGroup: mpgAddress, + operator: cvg.hxro().pdas().operator(), + dex: manifest.fields.dexProgram.programId, + operatorTrg: trgAccount.publicKey, + riskAndFeeSigner: dexterity.Manifest.GetRiskAndFeeSigner(mpgAddress), + traderRiskStateAcct: riskStateAccount.publicKey, + traderFeeStateAcct, + riskEngineProgram, + feeModelConfigAcct: feeModelConfigurationAcct, + feeModelProgram: feeModelProgramId, + systemProgram: systemProgram.address, + }, + hxroPrintTradeProviderProgram.address + ), + signers: [payer, riskStateAccount], + key: 'initializeOperatorTraderRiskGroup', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/lockHxroCollateral.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/lockHxroCollateral.ts new file mode 100644 index 000000000..fa9084044 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/lockHxroCollateral.ts @@ -0,0 +1,119 @@ +import BN from 'bn.js'; +import BigNumber from 'bignumber.js'; +import { getHxroProgramFromIDL } from '../program'; +import type { HxroContextHelper, HxroLeg } from '../printTrade'; +import { HXRO_LEG_DECIMALS } from '../constants'; +import { Convergence } from '@/Convergence'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; +import { PublicKey } from '@/types'; +import { + AuthoritySide, + PrintTradeResponse, + PrintTradeRfq, +} from '@/plugins/rfqModule'; + +export type LockHxroCollateralParams = { + rfq: PrintTradeRfq; + response: PrintTradeResponse; + side: AuthoritySide; + hxroContext: HxroContextHelper; +}; + +export const lockHxroCollateralBuilder = async ( + cvg: Convergence, + params: LockHxroCollateralParams, + options: TransactionBuilderOptions = {} +): Promise> => { + const { rfq, response, side, hxroContext } = params; + const { payer = cvg.rpc().getDefaultFeePayer() } = options; + + const { mpg, manifest } = hxroContext; + const userTrg = await hxroContext.getTrgDataBySide(side).get(); + + const [covarianceAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('s'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + const [correlationAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('r'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + const [markPricesAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('mark_prices'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + + const settlementResult = cvg.rfqs().getSettlementResult({ rfq, response }); + + const products = []; + for (let i = 0; i < 6; i++) { + if (i < rfq.legs.length) { + const legResult = settlementResult.legs[i]; + let amount = new BigNumber(legResult.amount).times( + new BigNumber(10).pow(HXRO_LEG_DECIMALS) + ); + if (legResult.receiver !== side) { + amount = amount.negated(); + } + + products.push({ + productIndex: new BN( + (rfq.legs[i] as HxroLeg).legInfo.productInfo.productIndex + ), + size: { m: new BN(amount.toString()), exp: new BN(HXRO_LEG_DECIMALS) }, + }); + } else { + products.push({ + productIndex: new BN(0), + size: { m: new BN(0), exp: new BN(0) }, + }); + } + } + + const idlProgram = await getHxroProgramFromIDL(cvg, manifest); + const instruction = await idlProgram.methods + .lockCollateral({ + numProducts: new BN(rfq.legs.length), + products, + }) + .accounts({ + user: payer.publicKey, + traderRiskGroup: hxroContext.getTrgBySide(side), + marketProductGroup: mpg.pubkey, + feeModelProgram: mpg.feeModelProgramId, + feeModelConfigurationAcct: mpg.feeModelConfigurationAcct, + feeOutputRegister: mpg.feeOutputRegister, + riskEngineProgram: mpg.riskEngineProgramId, + riskModelConfigurationAcct: mpg.riskModelConfigurationAcct, + riskOutputRegister: mpg.riskOutputRegister, + riskAndFeeSigner: hxroContext.getRiskAndFeeSigner(), + feeStateAcct: userTrg.feeStateAccount, + riskStateAcct: userTrg.riskStateAccount, + }) + .remainingAccounts([ + { + pubkey: covarianceAddress, + isSigner: false, + isWritable: true, + }, + { + pubkey: correlationAddress, + isSigner: false, + isWritable: true, + }, + { + pubkey: markPricesAddress, + isSigner: false, + isWritable: true, + }, + ]) + .instruction(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction, + signers: [payer], + key: 'lockHxroCollateral', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/modifyHxroConfig.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/modifyHxroConfig.ts new file mode 100644 index 000000000..c7bd49d70 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/modifyHxroConfig.ts @@ -0,0 +1,103 @@ +import { createModifyConfigInstruction } from '@convergence-rfq/hxro-print-trade-provider'; +import { configCache } from '../cache'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + PublicKey, + makeConfirmOptionsFinalizedOnMainnet, + useOperation, +} from '@/types'; +import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; + +const Key = 'ModifyHxroConfig' as const; + +export const modifyHxroConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type ModifyHxroConfigOperation = Operation< + typeof Key, + ModifyHxroConfigInput, + ModifyHxroConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type ModifyHxroConfigInput = { + validMpg: PublicKey; + + authority?: PublicKey; +}; + +/** + * @group Operations + * @category Outputs + */ +export type ModifyHxroConfigOutput = SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const modifyHxroConfigOperationHandler: OperationHandler = + { + handle: async ( + operation: ModifyHxroConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const builder = await modifyHxroBuilder(cvg, operation.input, scope); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + cvg, + scope.confirmOptions + ); + configCache.clear(); + const output = await builder.sendAndConfirm(cvg, confirmOptions); + scope.throwIfCanceled(); + return output.response; + }, + }; + +export const modifyHxroBuilder = async ( + cvg: Convergence, + params: ModifyHxroConfigInput, + options: TransactionBuilderOptions = {} +): Promise> => { + const { authority = cvg.identity().publicKey, validMpg } = params; + const { payer = cvg.rpc().getDefaultFeePayer() } = options; + + const hxroPrintTradeProviderProgram = cvg + .programs() + .getHxroPrintTradeProvider(); + + const protocol = cvg.protocol().pdas().protocol(); + const config = cvg.hxro().pdas().config(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction: createModifyConfigInstruction( + { + protocol, + authority, + config, + }, + { + validMpg, + }, + hxroPrintTradeProviderProgram.address + ), + signers: [payer], + key: 'ModifyHxroConfig', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/signHxroPrintTrade.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/signHxroPrintTrade.ts new file mode 100644 index 000000000..db67a8dfa --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/signHxroPrintTrade.ts @@ -0,0 +1,109 @@ +import BN from 'bn.js'; +import { SystemProgram } from '@solana/web3.js'; +import { getHxroProgramFromIDL } from '../program'; +import { numberToHxroFractional } from '../helpers'; +import type { HxroContextHelper, HxroLeg } from '../printTrade'; +import { Convergence } from '@/Convergence'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; +import { + AuthoritySide, + PrintTradeResponse, + PrintTradeRfq, +} from '@/plugins/rfqModule'; + +export type SignHxroPrintTradeParams = { + rfq: PrintTradeRfq; + response: PrintTradeResponse; + side: AuthoritySide; + hxroContext: HxroContextHelper; +}; + +export const signHxroPrintTradeBuilder = async ( + cvg: Convergence, + params: SignHxroPrintTradeParams, + options: TransactionBuilderOptions = {} +): Promise> => { + const { rfq, response, side, hxroContext } = params; + const { payer = cvg.rpc().getDefaultFeePayer() } = options; + + const settlementResult = cvg.rfqs().getSettlementResult({ rfq, response }); + const products = []; + for (let i = 0; i < 6; i++) { + if (i < rfq.legs.length) { + const legResult = settlementResult.legs[i]; + + const productIndex = new BN( + (rfq.legs[i] as HxroLeg).legInfo.productInfo.productIndex + ); + const size = numberToHxroFractional( + legResult.amount, + legResult.receiver === 'maker' + ); + + products.push({ + productIndex, + size, + }); + } else { + products.push({ + productIndex: new BN(0), + size: { m: new BN(0), exp: new BN(0) }, + }); + } + } + + const quoteSettlement = settlementResult.quote; + const price = numberToHxroFractional( + quoteSettlement.amount, + quoteSettlement.receiver == 'taker' + ); + + const printTradeSide = side === 'taker' ? { bid: {} } : { ask: {} }; + + const [creatorTrgData, counterpartyTrgData, operatorTrg] = await Promise.all([ + hxroContext.creatorTrgData.get(), + hxroContext.counterpartyTrgData.get(), + hxroContext.operatorTrg.get(), + ]); + + const idlProgram = await getHxroProgramFromIDL(cvg, hxroContext.manifest); + const instruction = await idlProgram.methods + .signPrintTrade({ + numProducts: new BN(rfq.legs.length), + products, + operatorCounterpartyFeeProportion: { m: new BN(0), exp: new BN(0) }, + operatorCreatorFeeProportion: { m: new BN(0), exp: new BN(0) }, + price, + side: printTradeSide, + }) + .accounts({ + user: payer.publicKey, + creator: hxroContext.getCreatorTrg(), + counterparty: hxroContext.getCounterpartyTrg(), + operator: operatorTrg, + marketProductGroup: hxroContext.mpg.pubkey, + printTrade: hxroContext.getPrintTrade(), + systemProgram: SystemProgram.programId, + feeModelProgram: hxroContext.mpg.feeModelProgramId, + feeModelConfigurationAcct: hxroContext.mpg.feeModelConfigurationAcct, + feeOutputRegister: hxroContext.mpg.feeOutputRegister, + riskEngineProgram: hxroContext.mpg.riskEngineProgramId, + riskModelConfigurationAcct: hxroContext.mpg.riskModelConfigurationAcct, + riskOutputRegister: hxroContext.mpg.riskOutputRegister, + riskAndFeeSigner: hxroContext.getRiskAndFeeSigner(), + creatorTraderFeeStateAcct: creatorTrgData.feeStateAccount, + creatorTraderRiskStateAcct: creatorTrgData.riskStateAccount, + counterpartyTraderFeeStateAcct: counterpartyTrgData.feeStateAccount, + counterpartyTraderRiskStateAcct: counterpartyTrgData.riskStateAccount, + seed: response.address, + }) + .instruction(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction, + signers: [payer], + key: 'signHxroPrintTrade', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/unlockHxroCollateralByRecord.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/unlockHxroCollateralByRecord.ts new file mode 100644 index 000000000..88fed30bc --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/operations/unlockHxroCollateralByRecord.ts @@ -0,0 +1,207 @@ +import { + LockedCollateralRecord, + LockedCollateralRecordArgs, + createRemoveLockedCollateralRecordInstruction, +} from '@convergence-rfq/hxro-print-trade-provider'; +import dexterity from '@hxronetwork/dexterity-ts'; + +import BN from 'bn.js'; +import { getHxroProgramFromIDL } from '../program'; +import { fetchValidHxroMpg } from '../helpers'; +import { hxroManifestCache } from '../cache'; +import { WithPubkey } from '../types'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + PublicKey, + useOperation, +} from '@/types'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; +import { SendAndConfirmTransactionResponse } from '@/plugins/rpcModule'; + +const Key = 'unlockHxroCollateralByRecord' as const; + +export const unlockHxroCollateralByRecordOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type UnlockHxroCollateralByRecordOperation = Operation< + typeof Key, + UnlockHxroCollateralByRecordInput, + UnlockHxroCollateralByRecordOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type UnlockHxroCollateralByRecordInput = { + lockRecord: PublicKey | WithPubkey; + + // 'unlock-and-remove-record' is a default action + action?: 'unlock' | 'remove-record' | 'unlock-and-remove-record'; +}; +/** + * @group Operations + * @category Outputs + */ +export type UnlockHxroCollateralByRecordOutput = + SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const unlockHxroCollateralByRecordOperationHandler: OperationHandler = + { + handle: async ( + operation: UnlockHxroCollateralByRecordOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const { + input: { lockRecord, action = 'unlock-and-remove-record' }, + } = operation; + + let lockRecordData: WithPubkey; + if ('publicKey' in lockRecord) { + lockRecordData = lockRecord; + } else { + const accountData = await LockedCollateralRecord.fromAccountAddress( + cvg.connection, + lockRecord + ); + lockRecordData = { ...accountData, publicKey: lockRecord }; + } + + const builder = TransactionBuilder.make().setFeePayer(cvg.identity()); + if (action == 'unlock' || action == 'unlock-and-remove-record') { + builder.add( + await unlockHxroCollateralBuilder( + cvg, + { + lockRecord: lockRecordData, + }, + scope + ) + ); + } + + if (action == 'remove-record' || action == 'unlock-and-remove-record') { + builder.add( + await removeLockCollateralRecordBuilder( + cvg, + { + lockRecord: lockRecordData, + }, + scope + ) + ); + } + + const output = await builder.sendAndConfirm(cvg, scope.confirmOptions); + return output.response; + }, + }; + +export const removeLockCollateralRecordBuilder = async ( + cvg: Convergence, + params: { lockRecord: WithPubkey }, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const { lockRecord } = params; + + return TransactionBuilder.make() + .setFeePayer(payer) + .add({ + instruction: createRemoveLockedCollateralRecordInstruction( + { + user: cvg.identity().publicKey, + lockedCollateralRecord: lockRecord.publicKey, + }, + cvg.programs().getHxroPrintTradeProvider(programs).address + ), + signers: [cvg.identity()], + key: 'removeLockCollateralRecord', + }); +}; + +export const unlockHxroCollateralBuilder = async ( + cvg: Convergence, + params: { lockRecord: LockedCollateralRecordArgs }, + options: TransactionBuilderOptions = {} +): Promise> => { + const { lockRecord } = params; + const { payer = cvg.rpc().getDefaultFeePayer() } = options; + + const manifest = await hxroManifestCache.get(cvg); + const mpg = await fetchValidHxroMpg(cvg, manifest); + + const userTrg = await manifest.getTRG(lockRecord.trg); + + const [covarianceAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('s'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + const [correlationAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('r'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + const [markPricesAddress] = PublicKey.findProgramAddressSync( + [Buffer.from('mark_prices'), mpg.pubkey.toBuffer()], + mpg.riskEngineProgramId + ); + + const idlProgram = await getHxroProgramFromIDL(cvg, manifest); + const instruction = await idlProgram.methods + .unlockCollateral({ + numProducts: new BN(6), + products: lockRecord.locks, + }) + .accounts({ + user: payer.publicKey, + traderRiskGroup: lockRecord.trg, + marketProductGroup: mpg.pubkey, + feeModelProgram: mpg.feeModelProgramId, + feeModelConfigurationAcct: mpg.feeModelConfigurationAcct, + feeOutputRegister: mpg.feeOutputRegister, + riskEngineProgram: mpg.riskEngineProgramId, + riskModelConfigurationAcct: mpg.riskModelConfigurationAcct, + riskOutputRegister: mpg.riskOutputRegister, + riskAndFeeSigner: dexterity.Manifest.GetRiskAndFeeSigner(mpg.pubkey), + feeStateAcct: userTrg.feeStateAccount, + riskStateAcct: userTrg.riskStateAccount, + }) + .remainingAccounts([ + { + pubkey: covarianceAddress, + isSigner: false, + isWritable: true, + }, + { + pubkey: correlationAddress, + isSigner: false, + isWritable: true, + }, + { + pubkey: markPricesAddress, + isSigner: false, + isWritable: true, + }, + ]) + .instruction(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction, + signers: [payer], + key: 'unlockHxroCollateral', + }); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/pdas.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/pdas.ts new file mode 100644 index 000000000..bc01a08aa --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/pdas.ts @@ -0,0 +1,29 @@ +import { Convergence } from '@/Convergence'; +import { Pda, Program, PublicKey } from '@/types'; + +export class HxroPdasClient { + constructor(protected readonly cvg: Convergence) {} + + config(): Pda { + const programId = this.programId(); + return Pda.find(programId, [Buffer.from('config', 'utf8')]); + } + + operator(): Pda { + const programId = this.programId(); + return Pda.find(programId, [Buffer.from('operator', 'utf8')]); + } + + lockedCollateralRecord(user: PublicKey, response: PublicKey): Pda { + const programId = this.programId(); + return Pda.find(programId, [ + Buffer.from('locked_collateral_record', 'utf8'), + user.toBuffer(), + response.toBuffer(), + ]); + } + + private programId(programs?: Program[]) { + return this.cvg.programs().getHxroPrintTradeProvider(programs).address; + } +} diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/plugin.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/plugin.ts new file mode 100644 index 000000000..ccc4f5ec0 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/plugin.ts @@ -0,0 +1,80 @@ +import { ProgramClient } from '../programModule'; +import { HxroClient } from './client'; +import { + fetchHxroPrintTradeProviderConfigOperation, + fetchHxroPrintTradeProviderConfigOperationHandler, + fetchHxroProductsOperation, + fetchHxroProductsOperationHandler, + fetchUnusedCollateralLockRecordsOperation, + fetchUnusedCollateralLockRecordsOperationHandler, + initializeHxroConfigOperation, + initializeHxroConfigOperationHandler, + initializeOperatorTraderRiskGroupOperation, + initializeOperatorTraderRiskGroupOperationHandler, + modifyHxroConfigOperation, + modifyHxroConfigOperationHandler, + unlockHxroCollateralByRecordOperation, + unlockHxroCollateralByRecordOperationHandler, +} from './operations'; +import { hxroPrintTradeProviderProgram } from './program'; +import { HxroPrintTradeParser } from './printTrade'; +import type { Convergence } from '@/Convergence'; +import { ConvergencePlugin, Program } from '@/types'; + +export const hxroModule = (): ConvergencePlugin => ({ + install(convergence: Convergence) { + convergence.programs().register(hxroPrintTradeProviderProgram); + convergence.programs().getHxroPrintTradeProvider = function ( + this: ProgramClient, + programs?: Program[] + ) { + return this.get(hxroPrintTradeProviderProgram.name, programs); + }; + + const op = convergence.operations(); + + op.register( + fetchHxroPrintTradeProviderConfigOperation, + fetchHxroPrintTradeProviderConfigOperationHandler + ); + op.register(fetchHxroProductsOperation, fetchHxroProductsOperationHandler); + op.register( + initializeHxroConfigOperation, + initializeHxroConfigOperationHandler + ); + op.register(modifyHxroConfigOperation, modifyHxroConfigOperationHandler); + op.register( + initializeOperatorTraderRiskGroupOperation, + initializeOperatorTraderRiskGroupOperationHandler + ); + op.register( + fetchUnusedCollateralLockRecordsOperation, + fetchUnusedCollateralLockRecordsOperationHandler + ); + op.register( + unlockHxroCollateralByRecordOperation, + unlockHxroCollateralByRecordOperationHandler + ); + + convergence.hxro = function () { + return new HxroClient(this); + }; + + convergence.addPrintTradeParser( + hxroPrintTradeProviderProgram.address, + new HxroPrintTradeParser() + ); + }, +}); + +declare module '../../Convergence' { + interface Convergence { + hxro(): HxroClient; + } +} + +declare module '../programModule/ProgramClient' { + interface ProgramClient { + getHxroPrintTradeProvider(programs?: Program[]): Program; + } +} diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/printTrade.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/printTrade.ts new file mode 100644 index 000000000..c50b47cf4 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/printTrade.ts @@ -0,0 +1,724 @@ +import { + futureCommonDataBeet, + optionCommonDataBeet, +} from '@convergence-rfq/risk-engine'; +import dexterity from '@hxronetwork/dexterity-ts'; +import BN from 'bn.js'; +import { + Leg as SolitaLeg, + QuoteAsset as SolitaQuoteAsset, +} from '@convergence-rfq/rfq'; +import { LockedCollateralRecord } from '@convergence-rfq/hxro-print-trade-provider'; +import { + AdditionalResponseData, + PrintTrade, + PrintTradeLeg, + PrintTradeParser, + PrintTradeQuote, +} from '../printTradeModule'; +import { fromNumberInstrumentType } from '../riskEngineModule'; +import { + AuthoritySide, + fromSolitaLegSide, + PrintTradeRfq, + PrintTradeResponse, +} from '../rfqModule'; +import { HXRO_LEG_DECIMALS, HXRO_QUOTE_DECIMALS } from './constants'; +import { HxroLegInput, HxroProductInfo } from './types'; +import { fetchValidHxroMpg, getFirstHxroExecutionOutput } from './helpers'; +import { hxroManifestCache } from './cache'; +import { + lockHxroCollateralBuilder, + removeLockCollateralRecordBuilder, + signHxroPrintTradeBuilder, + unlockHxroCollateralBuilder, +} from './operations'; +import { Convergence } from '@/Convergence'; +import { + PublicKey, + createSerializerFromFixedSizeBeet, + toFractional, +} from '@/types'; +import { + CvgCache, + TransactionBuilderOptions, + removeDecimals, + useCache, +} from '@/utils'; + +export class HxroPrintTrade implements PrintTrade { + constructor( + protected cvg: Convergence, + public takerTrg: PublicKey, + protected legsInfo: HxroLegInput[] + ) {} + + getPrintTradeProviderProgramId = () => + this.cvg.programs().getHxroPrintTradeProvider().address; + getLegs = () => this.legsInfo.map((legInfo) => new HxroLeg(legInfo)); + getQuote = () => new HxroQuote(this.takerTrg); + getValidationAccounts = async () => { + const { validMpg } = await this.cvg.hxro().fetchConfig(); + + const validationAccounts = this.legsInfo + .map((legInfo) => { + // TODO add in-place product fetching + if (legInfo.productInfo.productAddress === undefined) { + throw Error('Product addresses not fetched!'); + } + + const productAccountInfo = { + pubkey: legInfo.productInfo.productAddress, + isSigner: false, + isWritable: false, + }; + + const baseAssetAccountInfo = { + pubkey: this.cvg + .protocol() + .pdas() + .baseAsset({ index: legInfo.productInfo.baseAssetIndex }), + isSigner: false, + isWritable: false, + }; + + return [productAccountInfo, baseAssetAccountInfo]; + }) + .flat(); + + return [ + { + pubkey: this.cvg.hxro().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: validMpg, + isSigner: false, + isWritable: false, + }, + { + pubkey: this.takerTrg, + isSigner: false, + isWritable: false, + }, + ...validationAccounts, + ]; + }; + + getSettlementPreparations = async ( + rfq: PrintTradeRfq, + response: PrintTradeResponse, + side: AuthoritySide, + options: TransactionBuilderOptions + ) => { + const user = side === 'taker' ? rfq.taker : response.maker; + + const hxroContext = await HxroContextHelper.create( + this.cvg, + this, + response, + response.printTradeInitializedBy ?? side + ); + + const systemProgram = this.cvg.programs().getSystem(); + + const builders = [ + await lockHxroCollateralBuilder( + this.cvg, + { rfq, response, side, hxroContext }, + options + ), + ]; + if (response.printTradeInitializedBy !== null) { + builders.push( + await signHxroPrintTradeBuilder( + this.cvg, + { rfq, response, side, hxroContext }, + options + ) + ); + } + + const operatorTrg = await hxroContext.operatorTrg.get(); + + const accounts = [ + { + pubkey: this.cvg + .hxro() + .pdas() + .lockedCollateralRecord(user, response.address), + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg.hxro().pdas().operator(), + isSigner: false, + isWritable: false, + }, + { + pubkey: this.cvg.hxro().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.getDexProgramId(), + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.mpg.pubkey, + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg.identity().publicKey, + isSigner: true, + isWritable: false, + }, + { + pubkey: hxroContext.getTakerTrg(), + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.getMakerTrg(), + isSigner: false, + isWritable: true, + }, + { + pubkey: operatorTrg, + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.getPrintTrade(), + isSigner: false, + isWritable: true, + }, + { pubkey: systemProgram.address, isSigner: false, isWritable: false }, + ]; + + return { accounts, builders }; + }; + + getSettlementAccounts = async ( + rfq: PrintTradeRfq, + response: PrintTradeResponse + ) => { + const hxroContext = await HxroContextHelper.create( + this.cvg, + this, + response, + response.printTradeInitializedBy! + ); + const systemProgram = this.cvg.programs().getSystem(); + + const executionOutput = await getFirstHxroExecutionOutput( + this.cvg, + hxroContext.getDexProgramId() + ); + + const [creatorTrgData, counterpartyTrgData, operatorTrg] = + await Promise.all([ + hxroContext.creatorTrgData.get(), + hxroContext.counterpartyTrgData.get(), + hxroContext.operatorTrg.get(), + ]); + + return [ + { + pubkey: rfq.taker, + isSigner: false, + isWritable: true, + }, + { + pubkey: response.maker, + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg + .hxro() + .pdas() + .lockedCollateralRecord(rfq.taker, response.address), + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg + .hxro() + .pdas() + .lockedCollateralRecord(response.maker, response.address), + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg.hxro().pdas().operator(), + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg.hxro().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.getDexProgramId(), + isSigner: false, + isWritable: false, + }, + { pubkey: hxroContext.mpg.pubkey, isSigner: false, isWritable: true }, + { pubkey: hxroContext.getTakerTrg(), isSigner: false, isWritable: true }, + { pubkey: hxroContext.getMakerTrg(), isSigner: false, isWritable: true }, + { + pubkey: operatorTrg, + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.getPrintTrade(), + isSigner: false, + isWritable: true, + }, + { pubkey: executionOutput, isSigner: false, isWritable: true }, + { + pubkey: hxroContext.mpg.feeModelProgramId, + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.mpg.feeModelConfigurationAcct, + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.mpg.feeOutputRegister, + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.mpg.riskEngineProgramId, + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.mpg.riskModelConfigurationAcct, + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.mpg.riskOutputRegister, + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.getRiskAndFeeSigner(), + isSigner: false, + isWritable: false, + }, + { + pubkey: creatorTrgData.feeStateAccount, + isSigner: false, + isWritable: true, + }, + { + pubkey: creatorTrgData.riskStateAccount, + isSigner: false, + isWritable: true, + }, + { + pubkey: counterpartyTrgData.feeStateAccount, + isSigner: false, + isWritable: true, + }, + { + pubkey: counterpartyTrgData.riskStateAccount, + isSigner: false, + isWritable: true, + }, + { pubkey: systemProgram.address, isSigner: false, isWritable: false }, + ]; + }; + + getRevertPreparations = async ( + rfq: PrintTradeRfq, + response: PrintTradeResponse, + side: AuthoritySide, + options: TransactionBuilderOptions + ) => { + const user = side === 'taker' ? rfq.taker : response.maker; + + const postBuilders = []; + if (this.cvg.identity().publicKey.equals(user)) { + const lockRecordAddress = this.cvg + .hxro() + .pdas() + .lockedCollateralRecord(user, response.address); + + const accountData = await LockedCollateralRecord.fromAccountAddress( + this.cvg.connection, + lockRecordAddress + ); + const lockRecord = { ...accountData, publicKey: lockRecordAddress }; + + postBuilders.push( + await unlockHxroCollateralBuilder(this.cvg, { lockRecord }, options) + ); + postBuilders.push( + await removeLockCollateralRecordBuilder( + this.cvg, + { lockRecord }, + options + ) + ); + } + + const accounts = [ + { + pubkey: this.cvg + .hxro() + .pdas() + .lockedCollateralRecord(user, response.address), + isSigner: false, + isWritable: true, + }, + ]; + + return { accounts, postBuilders }; + }; + + getCleanUpAccounts = async ( + rfq: PrintTradeRfq, + response: PrintTradeResponse + ) => { + const hxroContext = await HxroContextHelper.create( + this.cvg, + this, + response, + response.printTradeInitializedBy! + ); + const systemProgram = this.cvg.programs().getSystem(); + const creator = + response.printTradeInitializedBy! === 'taker' + ? rfq.taker + : response.maker; + + const operatorTrg = await hxroContext.operatorTrg.get(); + + return [ + { + pubkey: this.cvg.hxro().pdas().operator(), + isSigner: false, + isWritable: true, + }, + { + pubkey: this.cvg.hxro().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: hxroContext.getDexProgramId(), + isSigner: false, + isWritable: false, + }, + { pubkey: hxroContext.mpg.pubkey, isSigner: false, isWritable: true }, + { pubkey: hxroContext.getTakerTrg(), isSigner: false, isWritable: true }, + { pubkey: hxroContext.getMakerTrg(), isSigner: false, isWritable: true }, + { + pubkey: operatorTrg, + isSigner: false, + isWritable: true, + }, + { + pubkey: hxroContext.getPrintTrade(), + isSigner: false, + isWritable: true, + }, + { pubkey: creator, isSigner: false, isWritable: true }, + { pubkey: systemProgram.address, isSigner: false, isWritable: false }, + ]; + }; + + // after an rfq is parsed from an on-chain data, as much data is possible is parsed from there + // but some product info is missing in the rfq on-chain data + // this method overwrites hxro product data and can be used to fill all the missing data + overwriteWithFullHxroProductData = (fullProductsData: HxroProductInfo[]) => { + for (const legInfo of this.legsInfo) { + const fullProductData = fullProductsData.find( + (data) => data.productIndex === legInfo.productInfo.productIndex + ); + + if (fullProductData === undefined) { + throw new Error( + `Missing a product by index ${legInfo.productInfo.productIndex}` + ); + } + + legInfo.productInfo = fullProductData; + } + }; + + getValidateResponseAccounts = async ( + additionalData: AdditionalResponseData | undefined + ) => { + if (!(additionalData instanceof HxroAdditionalRespondData)) { + throw new Error( + 'This rfq requires hxro-specific HxroAdditionalRespondData type passed as an additional response data' + ); + } + + return [ + { + pubkey: this.cvg.hxro().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: additionalData.makerTrg, + isSigner: false, + isWritable: false, + }, + ]; + }; +} + +export class HxroPrintTradeParser implements PrintTradeParser { + parsePrintTrade( + cvg: Convergence, + legs: SolitaLeg[], + quote: SolitaQuoteAsset + ): PrintTrade { + const parsedLegInfo = legs.map((leg): HxroLegInput => { + if (leg.settlementTypeMetadata.__kind == 'Instrument') { + throw new Error('Invalid settlement leg type'); + } + + const instrumentType = fromNumberInstrumentType( + leg.settlementTypeMetadata.instrumentType + ); + let productInfo; + if (instrumentType == 'option') { + const serializer = + createSerializerFromFixedSizeBeet(optionCommonDataBeet); + const legData = Buffer.from(leg.data); + const [optionData, offset] = serializer.deserialize(legData); + const productIndex = legData.readUInt8(offset); + + productInfo = { + instrumentType, + baseAssetIndex: leg.baseAssetIndex.value, + productIndex, + optionType: optionData.optionType, + strikePrice: toFractional( + optionData.strikePrice, + optionData.strikePriceDecimals + ), + expirationTimestamp: Number(optionData.expirationTimestamp), + }; + } else if ( + instrumentType == 'perp-future' || + instrumentType == 'term-future' + ) { + const serializer = + createSerializerFromFixedSizeBeet(futureCommonDataBeet); + const legData = Buffer.from(leg.data); + const [, offset] = serializer.deserialize(legData); + const productIndex = legData.readUInt8(offset); + + productInfo = { + instrumentType, + baseAssetIndex: leg.baseAssetIndex.value, + productIndex, + }; + } else { + throw new Error('Unsupporeted instrument type!'); + } + + return { + amount: removeDecimals(leg.amount, leg.amountDecimals), + side: fromSolitaLegSide(leg.side), + productInfo, + }; + }); + const takerTrg = new PublicKey(quote.data); + + return new HxroPrintTrade(cvg, takerTrg, parsedLegInfo); + } +} + +class HxroQuote implements PrintTradeQuote { + constructor(public takerTrg: PublicKey) {} + + getDecimals = () => HXRO_QUOTE_DECIMALS; + serializeInstrumentData = () => this.takerTrg.toBuffer(); +} + +export class HxroLeg implements PrintTradeLeg { + legType: 'printTrade'; + + constructor(public legInfo: HxroLegInput) { + this.legType = 'printTrade'; + } + + getInstrumentType = () => this.legInfo.productInfo.instrumentType; + getBaseAssetIndex = () => ({ + value: this.legInfo.productInfo.baseAssetIndex, + }); + getAmount = () => this.legInfo.amount; + getDecimals = () => HXRO_LEG_DECIMALS; + getSide = () => this.legInfo.side; + serializeInstrumentData = () => { + let riskEngineBuffer; + if (this.legInfo.productInfo.instrumentType == 'option') { + const serializer = + createSerializerFromFixedSizeBeet(optionCommonDataBeet); + riskEngineBuffer = serializer.serialize({ + optionType: this.legInfo.productInfo.optionType, + underlyingAmountPerContract: new BN(1), + underlyingAmountPerContractDecimals: 0, + strikePrice: this.legInfo.productInfo.strikePrice.mantissa, + strikePriceDecimals: this.legInfo.productInfo.strikePrice.decimals, + expirationTimestamp: new BN( + this.legInfo.productInfo.expirationTimestamp + ), + }); + } else { + const serializer = + createSerializerFromFixedSizeBeet(futureCommonDataBeet); + riskEngineBuffer = serializer.serialize({ + underlyingAmountPerContract: new BN(1), + underlyingAmountPerContractDecimals: 0, + }); + } + + const productInfoBuffer = Buffer.alloc(1); + productInfoBuffer.writeUInt8(this.legInfo.productInfo.productIndex); + + return Buffer.concat([riskEngineBuffer, productInfoBuffer]); + }; +} + +export class HxroAdditionalRespondData extends AdditionalResponseData { + constructor(public makerTrg: PublicKey) { + super(); + } + + serialize(): Buffer { + return this.makerTrg.toBuffer(); + } + + static deserialize(data: Uint8Array): HxroAdditionalRespondData { + const makerTrg = new PublicKey(data); + return new HxroAdditionalRespondData(makerTrg); + } +} + +export class HxroContextHelper { + public creatorTrgData: CvgCache; + public counterpartyTrgData: CvgCache; + public operatorTrg: CvgCache; + + private constructor( + private cvg: Convergence, + public manifest: any, + public mpg: any, + private printTrade: HxroPrintTrade, + private response: PrintTradeResponse, + private firstToPrepare: AuthoritySide + ) { + this.creatorTrgData = useCache( + async () => await this.manifest.getTRG(this.getCreatorTrg()) + ); + this.counterpartyTrgData = useCache( + async () => await this.manifest.getTRG(this.getCounterpartyTrg()) + ); + this.operatorTrg = useCache(async () => { + const operatorTrgs = await this.manifest.getTRGsOfOwner( + this.cvg.hxro().pdas().operator() + ); + const { pubkey } = operatorTrgs[0]; + return pubkey; + }); + } + + static async create( + cvg: Convergence, + printTrade: HxroPrintTrade, + response: PrintTradeResponse, + firstToPrepare: AuthoritySide + ) { + const manifest = await hxroManifestCache.get(cvg); + const mpg = await fetchValidHxroMpg(cvg, manifest); + + return new HxroContextHelper( + cvg, + manifest, + mpg, + printTrade, + response, + firstToPrepare + ); + } + + getTakerTrg() { + return this.printTrade.takerTrg; + } + + getMakerTrg() { + return HxroAdditionalRespondData.deserialize(this.response.additionalData) + .makerTrg; + } + + getCreatorTrg() { + return this.firstToPrepare === 'taker' + ? this.getTakerTrg() + : this.getMakerTrg(); + } + + getCounterpartyTrg() { + return this.firstToPrepare === 'taker' + ? this.getMakerTrg() + : this.getTakerTrg(); + } + + getPrintTrade() { + const [result] = PublicKey.findProgramAddressSync( + [ + Buffer.from('print_trade'), + this.getCreatorTrg().toBuffer(), + this.getCounterpartyTrg().toBuffer(), + this.response.address.toBuffer(), + ], + this.getDexProgramId() + ); + + return result; + } + + getDexProgramId() { + return this.manifest.fields.dexProgram.programId; + } + + getRiskAndFeeSigner() { + return dexterity.Manifest.GetRiskAndFeeSigner(this.mpg.pubkey); + } + + getTrgBySide(side: AuthoritySide) { + if (side === 'taker') { + return this.getTakerTrg(); + } + + return this.getMakerTrg(); + } + + getTrgDataBySide(side: AuthoritySide) { + const isFirstToPrepare = side === this.firstToPrepare; + + if (isFirstToPrepare) { + return this.creatorTrgData; + } + + return this.counterpartyTrgData; + } +} diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/program.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/program.ts new file mode 100644 index 000000000..d64705f04 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/program.ts @@ -0,0 +1,38 @@ +import { PROGRAM_ID as HXRO_PRINT_TRADE_PROVIDER_PROGRAM_ID } from '@convergence-rfq/hxro-print-trade-provider'; +import { + Program as AnchorProgram, + AnchorProvider, + Wallet, +} from '@coral-xyz/anchor'; +import { Keypair } from '@solana/web3.js'; +import { Convergence } from '@/Convergence'; +import { Program } from '@/types'; +import { GpaBuilder, NoopWallet } from '@/utils'; + +export const hxroPrintTradeProviderProgram: Program = { + name: 'HxroPrintTradeProviderProgram', + address: HXRO_PRINT_TRADE_PROVIDER_PROGRAM_ID, + gpaResolver: (convergence: Convergence) => { + return new GpaBuilder(convergence, HXRO_PRINT_TRADE_PROVIDER_PROGRAM_ID); + }, +}; + +export const getHxroProgramFromIDL = async ( + cvg: Convergence, + hxroManifest: any +) => { + const idl = await import('./dex.json'); + // @ts-ignore + const RISK_IDL: Idl = idl; + + const provider = new AnchorProvider( + cvg.connection, + new NoopWallet(Keypair.generate().publicKey) as Wallet, + {} + ); + return new AnchorProgram( + RISK_IDL, + hxroManifest.fields.dexProgram.programId, + provider + ); +}; diff --git a/packages/js/src/plugins/hxroPrintTradeProviderModule/types.ts b/packages/js/src/plugins/hxroPrintTradeProviderModule/types.ts new file mode 100644 index 000000000..7b6bc2298 --- /dev/null +++ b/packages/js/src/plugins/hxroPrintTradeProviderModule/types.ts @@ -0,0 +1,40 @@ +import { PublicKey } from '@solana/web3.js'; +import { OptionType } from '@convergence-rfq/risk-engine'; +import { LegSide } from '../rfqModule'; +import { Fraction } from '@/types'; + +export type HxroLegInput = { + amount: number; + side: LegSide; + productInfo: HxroProductInfo; +}; + +type HxroCommonProductInfo = { + productIndex: number; + // Can be missing in a case when parsed from a leg but the data haven't been extended with hxro product data + productAddress?: PublicKey; + baseAssetIndex: number; +}; +export type HxroOptionInfo = HxroCommonProductInfo & { + instrumentType: 'option'; + optionType: OptionType; + strikePrice: Fraction; + expirationTimestamp: number; +}; +export type HxroTermFutureInfo = HxroCommonProductInfo & { + instrumentType: 'term-future'; + // Can be missing in a case when parsed from a leg but the data haven't been extended with hxro product data + expirationTimestamp?: number; +}; +export type HxroPerpFutureInfo = HxroCommonProductInfo & { + instrumentType: 'perp-future'; +}; + +export type HxroProductInfo = + | HxroOptionInfo + | HxroTermFutureInfo + | HxroPerpFutureInfo; + +export type WithPubkey = T & { + publicKey: PublicKey; +}; diff --git a/packages/js/src/plugins/index.ts b/packages/js/src/plugins/index.ts index b0ec26b85..b71066ad2 100644 --- a/packages/js/src/plugins/index.ts +++ b/packages/js/src/plugins/index.ts @@ -18,4 +18,6 @@ export * from './protocolModule'; export * from './systemModule'; export * from './tokenModule'; export * from './accountModule'; +export * from './printTradeModule'; +export * from './hxroPrintTradeProviderModule'; export * from './whitelistModule'; diff --git a/packages/js/src/plugins/instrumentModule/InstrumentPdasClient.ts b/packages/js/src/plugins/instrumentModule/InstrumentPdasClient.ts index 8f36a8f70..6a4514d00 100644 --- a/packages/js/src/plugins/instrumentModule/InstrumentPdasClient.ts +++ b/packages/js/src/plugins/instrumentModule/InstrumentPdasClient.ts @@ -1,6 +1,6 @@ import { Buffer } from 'buffer'; -import { Rfq } from '../rfqModule'; +import { EscrowRfq } from '../rfqModule'; import type { Convergence } from '../../Convergence'; import { Pda, PublicKey } from '../../types'; @@ -40,7 +40,7 @@ type InstrumentEscrowInput = { index: number; /** The Rfq Model. */ - rfqModel: Rfq; + rfqModel: EscrowRfq; }; type QuoteEscrowInput = { diff --git a/packages/js/src/plugins/instrumentModule/methods.ts b/packages/js/src/plugins/instrumentModule/methods.ts index 78fe794c2..f122839cc 100644 --- a/packages/js/src/plugins/instrumentModule/methods.ts +++ b/packages/js/src/plugins/instrumentModule/methods.ts @@ -1,39 +1,37 @@ import { ApiLeg, QuoteAsset, legBeet } from '@convergence-rfq/rfq'; -import { AccountMeta } from '@solana/web3.js'; +import { AccountMeta, PublicKey } from '@solana/web3.js'; import { createSerializerFromFixableBeetArgsStruct } from '../../types'; import { addDecimals } from '../../utils/conversions'; import { toSolitaLegSide } from '../rfqModule/models/LegSide'; -import { PsyoptionsEuropeanInstrument } from '../psyoptionsEuropeanInstrumentModule'; -import { PsyoptionsAmericanInstrument } from '../psyoptionsAmericanInstrumentModule'; -import { SpotLegInstrument } from '../spotInstrumentModule'; +import { Protocol } from '../protocolModule'; import { LegInstrument, QuoteInstrument } from './types'; import { Convergence } from '@/Convergence'; -export function toLeg(legInstrument: LegInstrument): ApiLeg { +export function instrumentToSolitaLeg(legInstrument: LegInstrument): ApiLeg { return { - instrumentProgram: legInstrument.getProgramId(), + settlementTypeMetadata: { + __kind: 'Instrument', + instrumentIndex: legInstrument.getInstrumentIndex(), + }, baseAssetIndex: legInstrument.getBaseAssetIndex(), - instrumentData: legInstrument.serializeInstrumentData(), - instrumentAmount: addDecimals( - legInstrument.getAmount(), - legInstrument.getDecimals() - ), - instrumentDecimals: legInstrument.getDecimals(), + data: legInstrument.serializeInstrumentData(), + amount: addDecimals(legInstrument.getAmount(), legInstrument.getDecimals()), + amountDecimals: legInstrument.getDecimals(), side: toSolitaLegSide(legInstrument.getSide()), }; } -export function serializeAsLeg(legInstrument: LegInstrument) { +export function serializeInstrumentAsSolitaLeg(legInstrument: LegInstrument) { const legSerializer = createSerializerFromFixableBeetArgsStruct(legBeet); return legSerializer.serialize({ - ...toLeg(legInstrument), + ...instrumentToSolitaLeg(legInstrument), reserved: new Array(64).fill(0), }); } export function getSerializedLegLength(legInstrument: LegInstrument) { - return serializeAsLeg(legInstrument).length; + return serializeInstrumentAsSolitaLeg(legInstrument).length; } export function getProgramAccount(legInstrument: LegInstrument): AccountMeta { @@ -52,38 +50,37 @@ export function getValidationAccounts( ); } -export function toQuote(legInstrument: QuoteInstrument): QuoteAsset { +export function instrumentToQuote(legInstrument: QuoteInstrument): QuoteAsset { return { - instrumentProgram: legInstrument.getProgramId(), - instrumentData: legInstrument.serializeInstrumentData(), - instrumentDecimals: legInstrument.getDecimals(), + settlementTypeMetadata: { + __kind: 'Instrument', + instrumentIndex: legInstrument.getInstrumentIndex(), + }, + data: legInstrument.serializeInstrumentData(), + decimals: legInstrument.getDecimals(), }; } -//TODO: refactor this method to use instrument interface in the future -export const legToBaseAssetMint = async ( +export const legToBaseAssetMint = ( convergence: Convergence, leg: LegInstrument ) => { - if (leg instanceof PsyoptionsEuropeanInstrument) { - const euroMetaOptionMint = await convergence.tokens().findMintByAddress({ - address: leg.optionMint, - }); - - return euroMetaOptionMint; - } else if (leg instanceof PsyoptionsAmericanInstrument) { - const americanOptionMint = await convergence.tokens().findMintByAddress({ - address: leg.optionMint, - }); + return convergence.tokens().findMintByAddress({ + address: leg.getAssetMint(), + }); +}; - return americanOptionMint; - } else if (leg instanceof SpotLegInstrument) { - const mint = await convergence.tokens().findMintByAddress({ - address: leg.mintAddress, - }); +export const getInstrumentProgramIndex = ( + protocol: Protocol, + programAddress: PublicKey +) => { + const instrumentIndex = protocol.instruments.findIndex((instrument) => + instrument.programKey.equals(programAddress) + ); - return mint; + if (instrumentIndex === -1) { + throw Error('Cannot find spot instrument program in protocol!'); } - throw Error('Unsupported instrument!'); + return instrumentIndex; }; diff --git a/packages/js/src/plugins/instrumentModule/plugin.ts b/packages/js/src/plugins/instrumentModule/plugin.ts index 23c3a7f6a..4acc551b1 100644 --- a/packages/js/src/plugins/instrumentModule/plugin.ts +++ b/packages/js/src/plugins/instrumentModule/plugin.ts @@ -1,5 +1,6 @@ import { Leg as SolitaLeg } from '@convergence-rfq/rfq'; +import { Protocol } from '../protocolModule'; import { LegInstrument, LegInstrumentParser } from './types'; import type { Convergence } from '@/Convergence'; import { ConvergencePlugin, Program, PublicKey } from '@/types'; @@ -7,37 +8,44 @@ import { ConvergencePlugin, Program, PublicKey } from '@/types'; /** @group Plugins */ export const instrumentModule = (): ConvergencePlugin => ({ install(convergence: Convergence) { - const legInstrumentParsers: [PublicKey, LegInstrumentParser][] = []; + const legInstrumentParsers = new Map(); convergence.addLegInstrument = function ( - programAddress: PublicKey, + instrumentProgramAddress: PublicKey, factory: LegInstrumentParser ) { - const entry = legInstrumentParsers.find(([key]) => - programAddress.equals(key) - ); - - if (entry) { + if (legInstrumentParsers.has(instrumentProgramAddress.toBase58())) { throw new Error( - `Instrument for address ${programAddress.toString()} is already added!` + `Instrument for program ${instrumentProgramAddress} is already added!` ); } - legInstrumentParsers.push([programAddress, factory]); + legInstrumentParsers.set(instrumentProgramAddress.toBase58(), factory); }; - convergence.parseLegInstrument = function (leg: SolitaLeg) { - const factory = legInstrumentParsers.find(([key]) => - leg.instrumentProgram.equals(key) - )?.[1]; + convergence.parseLegInstrument = function ( + leg: SolitaLeg, + protocol: Protocol + ) { + if (leg.settlementTypeMetadata.__kind !== 'Instrument') { + throw new Error( + 'Leg is not settled as escrow, cannot parse as instrument' + ); + } + + const { instrumentIndex } = leg.settlementTypeMetadata; + const instrumentProgram = + protocol.instruments[instrumentIndex].programKey; + + const factory = legInstrumentParsers.get(instrumentProgram.toBase58()); if (!factory) { throw new Error( - `Missing leg instrument for address ${leg.instrumentProgram.toString()}` + `Missing leg instrument for program ${instrumentProgram}` ); } - return factory.parseFromLeg(convergence, leg); + return factory.parseFromLeg(convergence, leg, instrumentIndex); }; }, }); @@ -45,15 +53,16 @@ export const instrumentModule = (): ConvergencePlugin => ({ declare module '../../Convergence' { interface Convergence { addLegInstrument( - programAddress: PublicKey, + instrumentProgramAddress: PublicKey, factory: LegInstrumentParser ): void; - parseLegInstrument(leg: SolitaLeg): LegInstrument; + parseLegInstrument(leg: SolitaLeg, protocol: Protocol): LegInstrument; } } declare module '../programModule/ProgramClient' { interface ProgramClient { + // TODO remove getSpotInstrument(programs?: Program[]): Program; } } diff --git a/packages/js/src/plugins/instrumentModule/types.ts b/packages/js/src/plugins/instrumentModule/types.ts index dbbc788b3..9ed173cf8 100644 --- a/packages/js/src/plugins/instrumentModule/types.ts +++ b/packages/js/src/plugins/instrumentModule/types.ts @@ -6,14 +6,22 @@ import { Convergence } from '../../Convergence'; import { LegSide } from '../rfqModule/models/LegSide'; export interface LegInstrumentParser { - parseFromLeg(convergence: Convergence, leg: Leg): LegInstrument; + parseFromLeg( + convergence: Convergence, + leg: Leg, + instrumentIndex: number + ): LegInstrument; } export type CreateOptionInstrumentsResult = TransactionInstruction[]; export interface LegInstrument { + legType: 'escrow'; + + getInstrumentIndex: () => number; getProgramId: () => PublicKey; getBaseAssetIndex: () => BaseAssetIndex; + getAssetMint: () => PublicKey; getAmount: () => number; getDecimals: () => number; getSide: () => LegSide; @@ -33,6 +41,7 @@ export interface LegInstrument { // } export interface QuoteInstrument { + getInstrumentIndex: () => number; getProgramId: () => PublicKey; getDecimals: () => number; serializeInstrumentData: () => Buffer; diff --git a/packages/js/src/plugins/printTradeModule/index.ts b/packages/js/src/plugins/printTradeModule/index.ts new file mode 100644 index 000000000..a30d9d93c --- /dev/null +++ b/packages/js/src/plugins/printTradeModule/index.ts @@ -0,0 +1,3 @@ +export * from './types'; +export * from './methods'; +export * from './plugin'; diff --git a/packages/js/src/plugins/printTradeModule/methods.ts b/packages/js/src/plugins/printTradeModule/methods.ts new file mode 100644 index 000000000..20ce83827 --- /dev/null +++ b/packages/js/src/plugins/printTradeModule/methods.ts @@ -0,0 +1,59 @@ +import { ApiLeg, QuoteAsset, legBeet } from '@convergence-rfq/rfq'; +import { AccountMeta } from '@solana/web3.js'; +import { toSolitaLegSide } from '../rfqModule/models'; +import { toNumberInstrumentType } from '../riskEngineModule/models'; +import { PrintTrade, PrintTradeLeg, PrintTradeQuote } from './types'; +import { addDecimals } from '@/utils'; +import { createSerializerFromFixableBeetArgsStruct } from '@/types'; + +export function printTradeToSolitaLeg(printTradeLeg: PrintTradeLeg): ApiLeg { + return { + settlementTypeMetadata: { + __kind: 'PrintTrade', + instrumentType: toNumberInstrumentType(printTradeLeg.getInstrumentType()), + }, + baseAssetIndex: printTradeLeg.getBaseAssetIndex(), + data: printTradeLeg.serializeInstrumentData(), + amount: addDecimals(printTradeLeg.getAmount(), printTradeLeg.getDecimals()), + amountDecimals: printTradeLeg.getDecimals(), + side: toSolitaLegSide(printTradeLeg.getSide()), + }; +} + +export function serializePrintTradeAsSolitaLeg(printTradeLeg: PrintTradeLeg) { + const legSerializer = createSerializerFromFixableBeetArgsStruct(legBeet); + return legSerializer.serialize({ + ...printTradeToSolitaLeg(printTradeLeg), + reserved: new Array(64).fill(0), + }); +} + +export function printTradetoSolitaQuote( + printTradeQuote: PrintTradeQuote +): QuoteAsset { + return { + settlementTypeMetadata: { + __kind: 'PrintTrade', + instrumentType: toNumberInstrumentType('spot'), + }, + data: printTradeQuote.serializeInstrumentData(), + decimals: printTradeQuote.getDecimals(), + }; +} + +export function getPrintTradeProgramAccount( + printTrade: PrintTrade +): AccountMeta { + return { + pubkey: printTrade.getPrintTradeProviderProgramId(), + isSigner: false, + isWritable: false, + }; +} + +export function prependWithProviderProgram( + printTrade: PrintTrade, + accounts: AccountMeta[] +): AccountMeta[] { + return [getPrintTradeProgramAccount(printTrade)].concat(accounts); +} diff --git a/packages/js/src/plugins/printTradeModule/plugin.ts b/packages/js/src/plugins/printTradeModule/plugin.ts new file mode 100644 index 000000000..2b1fb5f0d --- /dev/null +++ b/packages/js/src/plugins/printTradeModule/plugin.ts @@ -0,0 +1,59 @@ +import { + Leg as SolitaLeg, + QuoteAsset as SolitaQuoteAsset, +} from '@convergence-rfq/rfq'; +import { PrintTrade, PrintTradeParser } from './types'; +import type { Convergence } from '@/Convergence'; +import { ConvergencePlugin, PublicKey } from '@/types'; + +/** @group Plugins */ +export const printTradeModule = (): ConvergencePlugin => ({ + install(cvg: Convergence) { + const printTradeParsers = new Map(); + + cvg.addPrintTradeParser = function ( + printTradeProviderProgramId: PublicKey, + factory: PrintTradeParser + ) { + if (printTradeParsers.has(printTradeProviderProgramId.toBase58())) { + throw new Error( + `Print trade provider for program ${printTradeProviderProgramId} is already added!` + ); + } + + printTradeParsers.set(printTradeProviderProgramId.toBase58(), factory); + }; + + cvg.parsePrintTrade = function ( + printTradeProviderProgramId: PublicKey, + legs: SolitaLeg[], + quoteAsset: SolitaQuoteAsset + ) { + const factory = printTradeParsers.get( + printTradeProviderProgramId.toBase58() + ); + + if (!factory) { + throw new Error( + `Missing print trade provider for program ${printTradeProviderProgramId}` + ); + } + + return factory.parsePrintTrade(cvg, legs, quoteAsset); + }; + }, +}); + +declare module '../../Convergence' { + interface Convergence { + addPrintTradeParser( + printTradeProviderProgramId: PublicKey, + factory: PrintTradeParser + ): void; + parsePrintTrade( + printTradeProviderProgramId: PublicKey, + legs: SolitaLeg[], + quoteAsset: SolitaQuoteAsset + ): PrintTrade; + } +} diff --git a/packages/js/src/plugins/printTradeModule/types.ts b/packages/js/src/plugins/printTradeModule/types.ts new file mode 100644 index 000000000..cc56c373e --- /dev/null +++ b/packages/js/src/plugins/printTradeModule/types.ts @@ -0,0 +1,73 @@ +import { AccountMeta, PublicKey } from '@solana/web3.js'; +import { + BaseAssetIndex, + Leg as SolitaLeg, + QuoteAsset as SolitaQuoteAsset, +} from '@convergence-rfq/rfq'; +import { InstrumentType } from '../riskEngineModule'; +import { + LegSide, + AuthoritySide, + PrintTradeResponse, + PrintTradeRfq, +} from '../rfqModule'; +import { Convergence } from '@/Convergence'; +import { TransactionBuilder, TransactionBuilderOptions } from '@/utils'; + +export interface PrintTrade { + getPrintTradeProviderProgramId: () => PublicKey; + getLegs: () => PrintTradeLeg[]; + getQuote: () => PrintTradeQuote; + getValidationAccounts: () => Promise; + getSettlementPreparations: ( + rfq: PrintTradeRfq, + response: PrintTradeResponse, + side: AuthoritySide, + options: TransactionBuilderOptions + ) => Promise<{ accounts: AccountMeta[]; builders: TransactionBuilder[] }>; + getSettlementAccounts: ( + rfq: PrintTradeRfq, + response: PrintTradeResponse + ) => Promise; + getRevertPreparations: ( + rfq: PrintTradeRfq, + response: PrintTradeResponse, + side: AuthoritySide, + options: TransactionBuilderOptions + ) => Promise<{ accounts: AccountMeta[]; postBuilders: TransactionBuilder[] }>; + getCleanUpAccounts: ( + rfq: PrintTradeRfq, + response: PrintTradeResponse + ) => Promise; + getValidateResponseAccounts: ( + additionalData: AdditionalResponseData | undefined + ) => Promise; +} + +export interface PrintTradeLeg { + legType: 'printTrade'; + + getInstrumentType: () => InstrumentType; + getBaseAssetIndex: () => BaseAssetIndex; + getAmount: () => number; + getDecimals: () => number; + getSide: () => LegSide; + serializeInstrumentData: () => Buffer; +} + +export interface PrintTradeQuote { + getDecimals: () => number; + serializeInstrumentData: () => Buffer; +} + +export interface PrintTradeParser { + parsePrintTrade( + cvg: Convergence, + legs: SolitaLeg[], + quote: SolitaQuoteAsset + ): PrintTrade; +} + +export abstract class AdditionalResponseData { + abstract serialize(): Buffer; +} diff --git a/packages/js/src/plugins/protocolModule/ProtocolClient.ts b/packages/js/src/plugins/protocolModule/ProtocolClient.ts index af32be4ed..207053bbe 100644 --- a/packages/js/src/plugins/protocolModule/ProtocolClient.ts +++ b/packages/js/src/plugins/protocolModule/ProtocolClient.ts @@ -19,6 +19,10 @@ import { getRegisteredMintsOperation, closeProtocolOperation, CloseProtocolInput, + AddPrintTradeProviderInput, + addPrintTradeProviderOperation, + ChangeBaseAssetParametersInput, + changeBaseAssetParametersOperation, updateBaseAssetOperation, UpdateBaseAssetInput, } from './operations'; @@ -74,6 +78,16 @@ export class ProtocolClient { .execute(addInstrumentOperation(input), options); } + /** {@inheritDoc addPrintTradeProviderOperation} */ + addPrintTradeProvider( + input: AddPrintTradeProviderInput, + options?: OperationOptions + ) { + return this.convergence + .operations() + .execute(addPrintTradeProviderOperation(input), options); + } + /** {@inheritDoc getProtocolOperation} */ get(input?: GetProtocolInput, options?: OperationOptions) { return this.convergence @@ -94,6 +108,16 @@ export class ProtocolClient { .execute(addBaseAssetOperation(input), options); } + /** {@inheritDoc changeBaseAssetParametersOperation} */ + changeBaseAssetParameters( + input: ChangeBaseAssetParametersInput, + options?: OperationOptions + ) { + return this.convergence + .operations() + .execute(changeBaseAssetParametersOperation(input), options); + } + /** {@inheritDoc registerMintOperation} */ registerMint(input: RegisterMintInput, options?: OperationOptions) { return this.convergence diff --git a/packages/js/src/plugins/protocolModule/models/BaseAsset.ts b/packages/js/src/plugins/protocolModule/models/BaseAsset.ts index a2d4b4caa..ff2abee70 100644 --- a/packages/js/src/plugins/protocolModule/models/BaseAsset.ts +++ b/packages/js/src/plugins/protocolModule/models/BaseAsset.ts @@ -19,8 +19,27 @@ export type RiskCategory = | 'custom-2' | 'custom-3'; +export const isRiskCategory = (value: string): value is RiskCategory => { + return [ + 'very-low', + 'low', + 'medium', + 'high', + 'very-high', + 'custom-1', + 'custom-2', + 'custom-3', + ].includes(value); +}; + +export type OracleSource = 'switchboard' | 'pyth' | 'in-place'; + +export const isOracleSource = (value: string): value is OracleSource => { + return ['switchboard', 'pyth', 'in-place'].includes(value); +}; + export type PriceOracle = { - source: 'switchboard' | 'pyth' | 'in-place'; + source: OracleSource; address?: PublicKey; price?: number; }; @@ -50,8 +69,17 @@ export type BaseAsset = { /** Is base asset enabled or disabled. */ readonly enabled: boolean; - /** The price oracle for the base asset. */ - readonly priceOracle: PriceOracle; + /** The price oracle source for the base asset. */ + readonly oracleSource: OracleSource; + + /** The switchboard oracle. */ + readonly switchboardOracle?: PublicKey; + + /** The pyth oracle. */ + readonly pythOracle?: PublicKey; + + /** The in-place price. */ + readonly inPlacePrice?: number; /** The ticker for the base asset. */ readonly ticker: string; @@ -97,31 +125,56 @@ export const toRiskCategory = ( } }; -/** @group Model Helpers */ -export const toPriceOracle = ( - solitaOracleSource: SolitaOracleSource, - switchboardOracle: PublicKey, - pythOracle: PublicKey, - inPlacePrice: number -): PriceOracle => { - switch (solitaOracleSource) { +export const toOracleSource = ( + oracleSource: SolitaOracleSource +): OracleSource => { + switch (oracleSource) { case SolitaOracleSource.Switchboard: + return 'switchboard'; + case SolitaOracleSource.Pyth: + return 'pyth'; + case SolitaOracleSource.InPlace: + return 'in-place'; + default: + throw new Error(`Unsupported oracle source: ${oracleSource}`); + } +}; + +export const toSolitaOracleSource = ( + oracleSource: OracleSource +): SolitaOracleSource => { + switch (oracleSource) { + case 'switchboard': + return SolitaOracleSource.Switchboard; + case 'pyth': + return SolitaOracleSource.Pyth; + case 'in-place': + return SolitaOracleSource.InPlace; + default: + throw new Error(`Unsupported oracle source: ${oracleSource}`); + } +}; + +/** @group Model Helpers */ +export const toPriceOracle = (baseAsset: BaseAsset): PriceOracle => { + switch (baseAsset.oracleSource) { + case 'switchboard': return { source: 'switchboard', - address: switchboardOracle, + address: baseAsset.switchboardOracle, }; - case SolitaOracleSource.Pyth: + case 'pyth': return { source: 'pyth', - address: pythOracle, + address: baseAsset.pythOracle, }; - case SolitaOracleSource.InPlace: + case 'in-place': return { source: 'in-place', - price: inPlacePrice, + price: baseAsset.inPlacePrice, }; default: - throw new Error(`Unsupported price oracle: ${solitaOracleSource}`); + throw new Error(`Unsupported price oracle: ${baseAsset.oracleSource}`); } }; @@ -195,11 +248,14 @@ export const toBaseAsset = (account: BaseAssetAccount): BaseAsset => ({ index: toBaseAssetIndex(account.data.index), enabled: account.data.enabled, riskCategory: toRiskCategory(account.data.riskCategory), - priceOracle: toPriceOracle( - account.data.oracleSource, - account.data.switchboardOracle, - account.data.pythOracle, - account.data.inPlacePrice - ), + oracleSource: toOracleSource(account.data.oracleSource), + switchboardOracle: !account.data.switchboardOracle.equals(PublicKey.default) + ? account.data.switchboardOracle + : undefined, + pythOracle: !account.data.pythOracle.equals(PublicKey.default) + ? account.data.pythOracle + : undefined, + inPlacePrice: + account.data.inPlacePrice !== 0 ? account.data.inPlacePrice : undefined, ticker: account.data.ticker, }); diff --git a/packages/js/src/plugins/protocolModule/models/Protocol.ts b/packages/js/src/plugins/protocolModule/models/Protocol.ts index f43a6039e..d265ffc43 100644 --- a/packages/js/src/plugins/protocolModule/models/Protocol.ts +++ b/packages/js/src/plugins/protocolModule/models/Protocol.ts @@ -1,5 +1,9 @@ import { PublicKey } from '@solana/web3.js'; -import { FeeParameters, Instrument } from '@convergence-rfq/rfq'; +import { + FeeParameters, + Instrument, + PrintTradeProvider, +} from '@convergence-rfq/rfq'; import { ProtocolAccount } from '../accounts'; import { assert } from '../../../utils/assert'; @@ -37,6 +41,9 @@ export type Protocol = { /** The procotol instruments. */ readonly instruments: Instrument[]; + + /** The procotol instruments. */ + readonly printTradeProviders: PrintTradeProvider[]; }; /** @group Model Helpers */ @@ -59,4 +66,5 @@ export const toProtocol = (account: ProtocolAccount): Protocol => ({ riskEngine: account.data.riskEngine, collateralMint: account.data.collateralMint, instruments: account.data.instruments, + printTradeProviders: account.data.printTradeProviders, }); diff --git a/packages/js/src/plugins/protocolModule/operations/addPrintTradeProvider.ts b/packages/js/src/plugins/protocolModule/operations/addPrintTradeProvider.ts new file mode 100644 index 000000000..734fc18d1 --- /dev/null +++ b/packages/js/src/plugins/protocolModule/operations/addPrintTradeProvider.ts @@ -0,0 +1,132 @@ +import { createAddPrintTradeProviderInstruction } from '@convergence-rfq/rfq'; +import { PublicKey } from '@solana/web3.js'; + +import { SendAndConfirmTransactionResponse } from '../../rpcModule'; +import { Convergence } from '../../../Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + useOperation, +} from '../../../types'; +import { + TransactionBuilder, + TransactionBuilderOptions, +} from '../../../utils/TransactionBuilder'; +import { protocolCache } from '../cache'; + +const Key = 'AddPrintTradeProviderOperation' as const; + +/** + * @group Operations + * @category Constructors + */ +export const addPrintTradeProviderOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type AddPrintTradeProviderOperation = Operation< + typeof Key, + AddPrintTradeProviderInput, + AddPrintTradeProviderOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type AddPrintTradeProviderInput = { + /** + * The print trade provider program to add to the protocol. + */ + printTradeProviderProgram: PublicKey; + + /* + * If true, settlement could expire and be cancelled if both parties have prepared but haven't settled + */ + settlementCanExpire: boolean; + + validateResponseAccountAmount: number; +}; + +/** + * @group Operations + * @category Outputs + */ +export type AddPrintTradeProviderOutput = { + /** The blockchain response from sending and confirming the transaction. */ + response: SendAndConfirmTransactionResponse; +}; + +/** + * @group Operations + * @category Handlers + */ +export const addPrintTradeProviderOperationHandler: OperationHandler = + { + handle: async ( + operation: AddPrintTradeProviderOperation, + convergence: Convergence, + scope: OperationScope + ): Promise => { + scope.throwIfCanceled(); + + protocolCache.clear(); + + return addPrintTradeProviderBuilder( + convergence, + operation.input, + scope + ).sendAndConfirm(convergence, scope.confirmOptions); + }, + }; + +/** + * @group Transaction Builders + * @category Inputs + */ +export type AddPrintTradeProviderBuilderParams = AddPrintTradeProviderInput; + +/** + * @group Transaction Builders + * @category Constructors + */ +export const addPrintTradeProviderBuilder = ( + cvg: Convergence, + params: AddPrintTradeProviderBuilderParams, + options: TransactionBuilderOptions = {} +): TransactionBuilder => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const rfqProgram = cvg.programs().getRfq(programs); + const { + printTradeProviderProgram, + settlementCanExpire, + validateResponseAccountAmount, + } = params; + const authority = cvg.identity(); + + // Clear the protocol cache so that the protocol is reloaded + protocolCache.clear(); + + return TransactionBuilder.make() + .setFeePayer(payer) + .add({ + instruction: createAddPrintTradeProviderInstruction( + { + authority: authority.publicKey, + protocol: cvg.protocol().pdas().protocol(), + printTradeProviderProgram, + }, + { + settlementCanExpire, + validateResponseAccountAmount, + }, + rfqProgram.address + ), + signers: [authority], + key: 'addPrintTradeProvider', + }); +}; diff --git a/packages/js/src/plugins/protocolModule/operations/changeBaseAssetParameters.ts b/packages/js/src/plugins/protocolModule/operations/changeBaseAssetParameters.ts new file mode 100644 index 000000000..70c34825a --- /dev/null +++ b/packages/js/src/plugins/protocolModule/operations/changeBaseAssetParameters.ts @@ -0,0 +1,178 @@ +import { createChangeBaseAssetParametersInstruction } from '@convergence-rfq/rfq'; +import { PublicKey } from '@solana/web3.js'; + +import { SendAndConfirmTransactionResponse } from '../../rpcModule'; +import { + RiskCategory, + toSolitaRiskCategory, + OracleSource, + toSolitaOracleSource, +} from '../models/BaseAsset'; +import { Convergence } from '../../../Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + useOperation, +} from '../../../types'; +import { + TransactionBuilder, + TransactionBuilderOptions, +} from '../../../utils/TransactionBuilder'; +import { baseAssetsCache } from '../cache'; + +const Key = 'changeBaseAssetParametersOperation' as const; + +/** + * @group Operations + * @category Constructors + */ +export const changeBaseAssetParametersOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type ChangeBaseAssetParametersOperation = Operation< + typeof Key, + ChangeBaseAssetParametersInput, + ChangeBaseAssetParametersOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type ChangeBaseAssetParametersInput = { + index: number; + + enabled?: boolean; + + riskCategory?: RiskCategory; + + /** + * If this parameter is missing, oracle source would be unchanged + * If a null value is passed, unset it + */ + oracleSource?: OracleSource; + + /** + * If this parameter is missing, switchboard oracle would be unchanged + * If a null value is passed, unset it + */ + switchboardOracle?: PublicKey | null; + + /** + * If this parameter is missing, pyth oracle would be unchanged + * If a null value is passed, unset it + */ + pythOracle?: PublicKey | null; + + /** + * If this parameter is missing, in place price would be unchanged + * If a null value is passed, unset it + */ + inPlacePrice?: number | null; +}; + +/** + * @group Operations + * @category Outputs + */ +export type ChangeBaseAssetParametersOutput = { + /** The blockchain response from sending and confirming the transaction. */ + response: SendAndConfirmTransactionResponse; +}; + +/** + * @group Operations + * @category Handlers + */ +export const changeBaseAssetParametersOperationHandler: OperationHandler = + { + handle: async ( + operation: ChangeBaseAssetParametersOperation, + convergence: Convergence, + scope: OperationScope + ): Promise => { + scope.throwIfCanceled(); + + const builder = changeBaseAssetParametersBuilder( + convergence, + operation.input, + scope + ); + const { response } = await builder.sendAndConfirm( + convergence, + scope.confirmOptions + ); + baseAssetsCache.clear(); + + return { response }; + }, + }; + +/** + * @group Transaction Builders + * @category Inputs + */ +export type ChangeBaseAssetParametersBuilderParams = + ChangeBaseAssetParametersInput; + +/** + * @group Transaction Builders + * @category Constructors + */ +export const changeBaseAssetParametersBuilder = ( + cvg: Convergence, + params: ChangeBaseAssetParametersBuilderParams, + options: TransactionBuilderOptions = {} +): TransactionBuilder => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const rfqProgram = cvg.programs().getRfq(programs); + const protocolPda = cvg.protocol().pdas().protocol(); + const { + index, + enabled, + riskCategory, + oracleSource, + switchboardOracle, + pythOracle, + inPlacePrice, + } = params; + + const baseAsset = cvg.protocol().pdas().baseAsset({ index }); + + const wrapInCustomOption = (value: T | undefined) => + value !== undefined + ? { __kind: 'Some' as const, value } + : { __kind: 'None' as const }; + + return TransactionBuilder.make() + .setFeePayer(payer) + .add({ + instruction: createChangeBaseAssetParametersInstruction( + { + authority: cvg.identity().publicKey, + protocol: protocolPda, + baseAsset, + }, + { + riskCategory: riskCategory + ? toSolitaRiskCategory(riskCategory) + : null, + enabled: enabled ?? null, + oracleSource: oracleSource + ? toSolitaOracleSource(oracleSource) + : null, + switchboardOracle: wrapInCustomOption(switchboardOracle), + pythOracle: wrapInCustomOption(pythOracle), + inPlacePrice: wrapInCustomOption(inPlacePrice), + }, + rfqProgram.address + ), + signers: [cvg.identity()], + key: 'changeBaseAssetParameters', + }); +}; diff --git a/packages/js/src/plugins/protocolModule/operations/index.ts b/packages/js/src/plugins/protocolModule/operations/index.ts index f2968fa9d..cd3af1c50 100644 --- a/packages/js/src/plugins/protocolModule/operations/index.ts +++ b/packages/js/src/plugins/protocolModule/operations/index.ts @@ -1,6 +1,8 @@ export * from './initializeProtocol'; export * from './getProtocol'; export * from './addInstrument'; +export * from './changeBaseAssetParameters'; +export * from './addPrintTradeProvider'; export * from './registerMint'; export * from './addBaseAsset'; export * from './getBaseAssets'; diff --git a/packages/js/src/plugins/protocolModule/plugin.ts b/packages/js/src/plugins/protocolModule/plugin.ts index ba528a2a5..881e8718d 100644 --- a/packages/js/src/plugins/protocolModule/plugin.ts +++ b/packages/js/src/plugins/protocolModule/plugin.ts @@ -20,6 +20,10 @@ import { findBaseAssetByAddressOperationHandler, closeProtocolOperation, closeProtocolOperationHandler, + addPrintTradeProviderOperation, + addPrintTradeProviderOperationHandler, + changeBaseAssetParametersOperation, + changeBaseAssetParametersOperationHandler, updateBaseAssetOperation, updateBaseAssetOperationHandler, } from './operations'; @@ -37,7 +41,15 @@ export const protocolModule = (): ConvergencePlugin => ({ ); op.register(getProtocolOperation, getProtocolOperationHandler); op.register(addInstrumentOperation, addInstrumentOperationHandler); + op.register( + addPrintTradeProviderOperation, + addPrintTradeProviderOperationHandler + ); op.register(addBaseAssetOperation, addBaseAssetOperationHandler); + op.register( + changeBaseAssetParametersOperation, + changeBaseAssetParametersOperationHandler + ); op.register(registerMintOperation, registerMintOperationHandler); op.register(getBaseAssetsOperation, getBaseAssetsOperationHandler); op.register( @@ -68,6 +80,7 @@ declare module '../../Convergence' { declare module '../protocolModule/ProtocolClient' { interface ProtocolClient { + // TODO this method actually does not exist getProtocol(): Protocol; } } diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts index cd5fc7267..4ee5c4400 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/helpers.ts @@ -6,8 +6,10 @@ import { Convergence } from '../../Convergence'; import { getOrCreateATAtxBuilder } from '../../utils/ata'; import { NoopWallet } from '../../utils/Wallets'; import { InstructionUniquenessTracker } from '../../utils/classes'; -import { PsyoptionsAmericanInstrument } from './types'; -import { createAmericanProgram } from './instrument'; +import { + PsyoptionsAmericanInstrument, + createAmericanProgram, +} from './instrument'; import { TransactionBuilder } from '@/utils/TransactionBuilder'; export type PrepareAmericanOptionsResult = { diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts index 84ce0cd7e..d450d97bf 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/instrument.ts @@ -9,14 +9,16 @@ import * as psyoptionsAmerican from '@mithraic-labs/psy-american'; import BN from 'bn.js'; import { Mint } from '../tokenModule'; import { - CreateOptionInstrumentsResult, LegInstrument, + getInstrumentProgramIndex, + CreateOptionInstrumentsResult, } from '../instrumentModule'; import { addDecimals, removeDecimals } from '../../utils/conversions'; import { Convergence } from '../../Convergence'; import { createSerializerFromFixableBeetArgsStruct } from '../../types'; import { LegSide, fromSolitaLegSide } from '../rfqModule/models/LegSide'; import { NoopWallet } from '../../utils/Wallets'; +import { PSYOPTIONS_AMERICAN_INSTRUMENT_PROGRAM_ID } from './types'; import { GetOrCreateATAtxBuilderReturnType, getOrCreateATAtxBuilder, @@ -52,6 +54,7 @@ export const psyoptionsAmericanInstrumentDataSerializer = export class PsyoptionsAmericanInstrument implements LegInstrument { static readonly decimals = 0; + legType: 'escrow'; constructor( readonly convergence: Convergence, @@ -64,13 +67,18 @@ export class PsyoptionsAmericanInstrument implements LegInstrument { readonly optionMint: PublicKey, readonly optionMetaPubKey: PublicKey, readonly baseAssetIndex: BaseAssetIndex, + readonly instrumentIndex: number, readonly amount: number, readonly side: LegSide, readonly underlyingAssetMint?: PublicKey, readonly stableAssetMint?: PublicKey - ) {} + ) { + this.legType = 'escrow'; + } getBaseAssetIndex = () => this.baseAssetIndex; + getInstrumentIndex = () => this.instrumentIndex; + getAssetMint = () => this.optionMint; getAmount = () => this.amount; getDecimals = () => PsyoptionsAmericanInstrument.decimals; getSide = () => this.side; @@ -123,6 +131,11 @@ export class PsyoptionsAmericanInstrument implements LegInstrument { throw Error('Stablecoin mint cannot be used in a leg!'); } + const instrumentIndex = getInstrumentProgramIndex( + await convergence.protocol().get(), + PSYOPTIONS_AMERICAN_INSTRUMENT_PROGRAM_ID + ); + const cvgWallet = new NoopWallet(taker); const americanProgram = await createAmericanProgram(convergence, cvgWallet); const { optionMint, metaKey } = await getAmericanOptionkeys( @@ -145,6 +158,7 @@ export class PsyoptionsAmericanInstrument implements LegInstrument { optionMint, metaKey, mintInfo.mintType.baseAssetIndex, + instrumentIndex, amount, side, underlyingMint.address, @@ -246,9 +260,10 @@ export class PsyoptionsAmericanInstrument implements LegInstrument { export const psyoptionsAmericanInstrumentParser = { parseFromLeg( convergence: Convergence, - leg: Leg + leg: Leg, + instrumentIndex: number ): PsyoptionsAmericanInstrument { - const { side, instrumentAmount, instrumentData, baseAssetIndex } = leg; + const { side, amount, data, baseAssetIndex } = leg; const [ { optionType, @@ -261,7 +276,7 @@ export const psyoptionsAmericanInstrumentParser = { metaKey, }, ] = psyoptionsAmericanInstrumentDataSerializer.deserialize( - Buffer.from(instrumentData) + Buffer.from(data) ); return new PsyoptionsAmericanInstrument( @@ -278,7 +293,8 @@ export const psyoptionsAmericanInstrumentParser = { optionMint, metaKey, baseAssetIndex, - removeDecimals(instrumentAmount, PsyoptionsAmericanInstrument.decimals), + instrumentIndex, + removeDecimals(amount, PsyoptionsAmericanInstrument.decimals), fromSolitaLegSide(side) ); }, diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/plugin.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/plugin.ts index 54e73f71c..627ea33cc 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/plugin.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/plugin.ts @@ -21,7 +21,7 @@ export const psyoptionsAmericanInstrumentModule = (): ConvergencePlugin => ({ }; convergence.addLegInstrument( - PSYOPTIONS_AMERICAN_INSTRUMENT_PROGRAM_ID, + psyoptionsAmericanInstrumentProgram.address, psyoptionsAmericanInstrumentParser ); }, diff --git a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/types.ts b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/types.ts index 6ea177021..254cf4474 100644 --- a/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/types.ts +++ b/packages/js/src/plugins/psyoptionsAmericanInstrumentModule/types.ts @@ -1,4 +1,3 @@ export type { OptionMarket } from '@mithraic-labs/psy-american'; export { PROGRAM_ID as PSYOPTIONS_AMERICAN_INSTRUMENT_PROGRAM_ID } from '@convergence-rfq/psyoptions-american-instrument'; export { OptionType } from '@mithraic-labs/tokenized-euros'; -export { PsyoptionsAmericanInstrument } from './instrument'; diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/instrument.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/instrument.ts index 9ae177065..d11a03e11 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/instrument.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/instrument.ts @@ -15,14 +15,16 @@ import * as psyoptionsEuropean from '@mithraic-labs/tokenized-euros'; import * as anchor from '@project-serum/anchor'; import { Mint } from '../tokenModule'; import { - CreateOptionInstrumentsResult, LegInstrument, + getInstrumentProgramIndex, + CreateOptionInstrumentsResult, } from '../instrumentModule'; import { addDecimals, removeDecimals } from '../../utils/conversions'; import { assert } from '../../utils/assert'; import { Convergence } from '../../Convergence'; import { createSerializerFromFixableBeetArgsStruct } from '../../types'; import { LegSide, fromSolitaLegSide } from '../rfqModule/models/LegSide'; +import { PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ID } from './types'; import { NoopWallet } from '@/utils'; export const createEuropeanProgram = async ( @@ -102,6 +104,7 @@ const euroMetaSerializer = createSerializerFromFixableBeetArgsStruct( */ export class PsyoptionsEuropeanInstrument implements LegInstrument { static readonly decimals = 4; + legType: 'escrow'; constructor( readonly convergence: Convergence, @@ -114,15 +117,20 @@ export class PsyoptionsEuropeanInstrument implements LegInstrument { readonly optionMint: PublicKey, readonly optionMetaPubKey: PublicKey, readonly baseAssetIndex: BaseAssetIndex, + readonly instrumentIndex: number, readonly amount: number, readonly side: LegSide, readonly underlyingAssetMint?: PublicKey, readonly stableAssetMint?: PublicKey, readonly oracleAddress?: PublicKey, readonly oracleProviderId?: number - ) {} + ) { + this.legType = 'escrow'; + } + getInstrumentIndex = () => this.instrumentIndex; getBaseAssetIndex = () => this.baseAssetIndex; + getAssetMint = () => this.optionMint; getAmount = () => this.amount; getDecimals = () => PsyoptionsEuropeanInstrument.decimals; getSide = () => this.side; @@ -184,6 +192,10 @@ export class PsyoptionsEuropeanInstrument implements LegInstrument { throw Error('Stablecoin mint cannot be used in a leg!'); } + const instrumentIndex = getInstrumentProgramIndex( + await convergence.protocol().get(), + PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ID + ); const europeanProgram: any = await createEuropeanProgram( convergence, taker @@ -209,6 +221,7 @@ export class PsyoptionsEuropeanInstrument implements LegInstrument { optionMint, metaKey, mintInfo.mintType.baseAssetIndex, + instrumentIndex, amount, side, underlyingMint.address, @@ -292,9 +305,10 @@ export class PsyoptionsEuropeanInstrument implements LegInstrument { export const psyoptionsEuropeanInstrumentParser = { parseFromLeg( convergence: Convergence, - leg: Leg + leg: Leg, + instrumentIndex: number ): PsyoptionsEuropeanInstrument { - const { side, instrumentAmount, instrumentData, baseAssetIndex } = leg; + const { side, amount, data, baseAssetIndex } = leg; const [ { optionType, @@ -307,7 +321,7 @@ export const psyoptionsEuropeanInstrumentParser = { metaKey, }, ] = psyoptionsEuropeanInstrumentDataSerializer.deserialize( - Buffer.from(instrumentData) + Buffer.from(data) ); return new PsyoptionsEuropeanInstrument( @@ -324,7 +338,8 @@ export const psyoptionsEuropeanInstrumentParser = { optionMint, metaKey, baseAssetIndex, - removeDecimals(instrumentAmount, PsyoptionsEuropeanInstrument.decimals), + instrumentIndex, + removeDecimals(amount, PsyoptionsEuropeanInstrument.decimals), fromSolitaLegSide(side) ); }, diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/plugin.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/plugin.ts index b20fc6902..f5e0bb63f 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/plugin.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/plugin.ts @@ -1,6 +1,6 @@ -import { PROGRAM_ID } from '@convergence-rfq/psyoptions-european-instrument'; import { ProgramClient } from '../programModule'; import { psyoptionsEuropeanInstrumentParser } from './instrument'; +import { PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ID } from './types'; import { ConvergencePlugin, Program } from '@/types'; import type { Convergence } from '@/Convergence'; @@ -9,7 +9,7 @@ export const psyoptionsEuropeanInstrumentModule = (): ConvergencePlugin => ({ install(convergence: Convergence) { const psyoptionsEuropeanInstrumentProgram = { name: 'PsyoptionsEuropeanInstrumentProgram', - address: PROGRAM_ID, + address: PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ID, }; convergence.programs().register(psyoptionsEuropeanInstrumentProgram); diff --git a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/types.ts b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/types.ts index 9eb29fa4b..78763f8f2 100644 --- a/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/types.ts +++ b/packages/js/src/plugins/psyoptionsEuropeanInstrumentModule/types.ts @@ -1,3 +1,3 @@ -export { PROGRAM_ADDRESS as PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ADDRESS } from '@convergence-rfq/psyoptions-european-instrument'; +export { PROGRAM_ID as PSYOPTIONS_EUROPEAN_INSTRUMENT_PROGRAM_ID } from '@convergence-rfq/psyoptions-european-instrument'; export type { EuroMeta } from '@convergence-rfq/psyoptions-european-instrument'; export { OptionType } from '@mithraic-labs/tokenized-euros'; diff --git a/packages/js/src/plugins/rfqModule/RfqClient.ts b/packages/js/src/plugins/rfqModule/RfqClient.ts index d5e6385d5..98b3e02da 100644 --- a/packages/js/src/plugins/rfqModule/RfqClient.ts +++ b/packages/js/src/plugins/rfqModule/RfqClient.ts @@ -39,12 +39,8 @@ import { FindResponsesByRfqInput, findResponsesByOwnerOperation, FindResponsesByOwnerInput, - partiallySettleLegsOperation, - PartiallySettleLegsInput, partlyRevertSettlementPreparationOperation, PartlyRevertSettlementPreparationInput, - partiallySettleLegsAndSettleOperation, - PartiallySettleLegsAndSettleInput, revertSettlementPreparationOperation, RevertSettlementPreparationInput, prepareMoreLegsSettlementOperation, @@ -57,14 +53,6 @@ import { RespondToRfqInput, settleOperation, SettleInput, - settleOnePartyDefaultOperation, - SettleOnePartyDefaultInput, - settleTwoPartyDefaultOperation, - SettleTwoPartyDefaultInput, - unlockResponseCollateralOperation, - UnlockResponseCollateralInput, - unlockRfqCollateralOperation, - UnlockRfqCollateralInput, createAndFinalizeRfqConstructionOperation, CleanUpRfqsInput, cleanUpRfqsOperation, @@ -72,12 +60,12 @@ import { CleanUpResponseInput, cleanUpResponsesOperation, CleanUpResponsesInput, - unlockResponsesCollateralOperation, - UnlockResponsesCollateralInput, - UnlockRfqsCollateralInput, - unlockRfqsCollateralOperation, GetSettlementResultInput, getSettlementResultOperation, + CreatePrintTradeRfqInput, + createPrintTradeRfqOperation, + preparePrintTradeSettlementOperation, + PreparePrintTradeSettlementInput, getSettlementResultHandler, GetResponseStateAndActionInput, getResponseStateAndActionOperation, @@ -247,6 +235,16 @@ export class RfqClient { .execute(finalizeRfqConstructionOperation(input), options); } + /** {@inheritDoc createPrintTradeRfqOperation} */ + createPrintTrade( + input: CreatePrintTradeRfqInput, + options?: OperationOptions + ) { + return this.convergence + .operations() + .execute(createPrintTradeRfqOperation(input), options); + } + /** {@inheritDoc findResponseByAddressOperation} */ findResponseByAddress( input: FindResponseByAddressInput, @@ -290,16 +288,6 @@ export class RfqClient { .execute(findRfqByAddressOperation(input), options); } - /** {@inheritDoc partiallySettleLegsOperation} */ - partiallySettleLegs( - input: PartiallySettleLegsInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(partiallySettleLegsOperation(input), options); - } - /** {@inheritDoc partlyRevertSettlementPreparationOperation} */ partlyRevertSettlementPreparation( input: PartlyRevertSettlementPreparationInput, @@ -310,16 +298,6 @@ export class RfqClient { .execute(partlyRevertSettlementPreparationOperation(input), options); } - /** {@inheritDoc partiallySettleLegsAndSettleOperation} */ - partiallySettleLegsAndSettle( - input: PartiallySettleLegsAndSettleInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(partiallySettleLegsAndSettleOperation(input), options); - } - /** {@inheritDoc revertSettlementPreparationOperation} */ revertSettlementPreparation( input: RevertSettlementPreparationInput, @@ -357,6 +335,16 @@ export class RfqClient { .execute(prepareSettlementAndPrepareMoreLegsOperation(input), options); } + /** {@inheritDoc preparePrintTradeSettlementOperation} */ + preparePrintTradeSettlement( + input: PreparePrintTradeSettlementInput, + options?: OperationOptions + ) { + return this.convergence + .operations() + .execute(preparePrintTradeSettlementOperation(input), options); + } + /** * Helper method that refetches a given model * and returns an instance of the same type. @@ -419,66 +407,6 @@ export class RfqClient { .execute(settleOperation(input), options); } - /** {@inheritDoc settleOnePartyDefaultOperation} */ - settleOnePartyDefault( - input: SettleOnePartyDefaultInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(settleOnePartyDefaultOperation(input), options); - } - - /** {@inheritDoc settleTwoPartyDefaultOperation} */ - settleTwoPartyDefault( - input: SettleTwoPartyDefaultInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(settleTwoPartyDefaultOperation(input), options); - } - - /** {@inheritDoc unlockResponseCollateralOperation} */ - unlockResponseCollateral( - input: UnlockResponseCollateralInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(unlockResponseCollateralOperation(input), options); - } - - /** {@inheritDoc unlockResponsesCollateralOperation} */ - unlockResponsesCollateral( - input: UnlockResponsesCollateralInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(unlockResponsesCollateralOperation(input), options); - } - - /** {@inheritDoc unlockRfqCollateralOperation} */ - unlockRfqCollateral( - input: UnlockRfqCollateralInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(unlockRfqCollateralOperation(input), options); - } - - /** {@inheritDoc unlockRfqsCollateralOperation} */ - unlockRfqsCollateral( - input: UnlockRfqsCollateralInput, - options?: OperationOptions - ) { - return this.convergence - .operations() - .execute(unlockRfqsCollateralOperation(input), options); - } - /** {@inheritDoc sendTokensOperation} */ send( input: PartialKeys, diff --git a/packages/js/src/plugins/rfqModule/RfqPdasClient.ts b/packages/js/src/plugins/rfqModule/RfqPdasClient.ts index ac539fa9a..e53c41a2b 100644 --- a/packages/js/src/plugins/rfqModule/RfqPdasClient.ts +++ b/packages/js/src/plugins/rfqModule/RfqPdasClient.ts @@ -4,15 +4,14 @@ import { FixedSize as SolitaFixedSize, OrderType as SolitaOrderType, QuoteAsset, - QuoteRecord, - FixedSizeRecord, Quote, - priceQuoteBeet, + quoteBeet, + quoteAssetBeet, + fixedSizeBeet, } from '@convergence-rfq/rfq'; -import * as anchor from '@project-serum/anchor'; import * as beet from '@convergence-rfq/beet'; -import * as beetSolana from '@convergence-rfq/beet-solana'; +import BN from 'bn.js'; import { createSerializerFromFixableBeetArgsStruct, createSerializerFromFixableBeet, @@ -54,7 +53,7 @@ export class RfqPdasClient { const programId = this.programId(); return Pda.find(programId, [ Buffer.from('mint_info', 'utf8'), - quoteAsset.instrumentData, + quoteAsset.data, ]); } @@ -62,6 +61,7 @@ export class RfqPdasClient { rfq({ taker, legsHash, + printTradeProvider, orderType, quoteAsset, fixedSize, @@ -79,11 +79,10 @@ export class RfqPdasClient { Buffer.from('rfq', 'utf8'), taker.toBuffer(), legsHash, + (printTradeProvider || PublicKey.default).toBuffer(), serializeOrderTypeData(toSolitaOrderType(orderType)), quoteHash, - serializeFixedSizeData( - toSolitaFixedSize(fixedSize, quoteAsset.instrumentDecimals) - ), + serializeFixedSizeData(toSolitaFixedSize(fixedSize, quoteAsset.decimals)), toLittleEndian(activeWindow, 4), toLittleEndian(settlingWindow, 4), recentTimestamp.toArrayLike(Buffer, 'le', 8), @@ -127,42 +126,12 @@ const serializeOrderTypeData = (orderType: SolitaOrderType): Buffer => { }; const serializeQuoteData = (quote: Quote): Buffer => { - const quoteBeet = beet.dataEnum([ - [ - 'Standard', - new beet.FixableBeetArgsStruct( - [ - ['priceQuote', priceQuoteBeet], - ['legsMultiplierBps', beet.u64], - ], - 'QuoteRecord["Standard"]' - ), - ], - - [ - 'FixedSize', - new beet.FixableBeetArgsStruct( - [['priceQuote', priceQuoteBeet]], - 'QuoteRecord["FixedSize"]' - ), - ], - ]) as beet.FixableBeet; - const quoteSerializer = createSerializerFromFixableBeet(quoteBeet); return quoteSerializer.serialize(quote); }; const serializeQuoteAssetData = (quoteAsset: QuoteAsset): Buffer => { - const quoteAssetBeet = new beet.FixableBeetArgsStruct( - [ - ['instrumentProgram', beetSolana.publicKey], - ['instrumentData', beet.bytes], - ['instrumentDecimals', beet.u8], - ], - 'QuoteAsset' - ); - const quoteAssetSerializer = createSerializerFromFixableBeetArgsStruct(quoteAssetBeet); @@ -170,32 +139,6 @@ const serializeQuoteAssetData = (quoteAsset: QuoteAsset): Buffer => { }; const serializeFixedSizeData = (fixedSize: SolitaFixedSize): Buffer => { - const fixedSizeBeet = beet.dataEnum([ - [ - 'None', - new beet.BeetArgsStruct( - [['padding', beet.u64]], - 'FixedSizeRecord["None"]' - ), - ], - - [ - 'BaseAsset', - new beet.BeetArgsStruct( - [['legsMultiplierBps', beet.u64]], - 'FixedSizeRecord["BaseAsset"]' - ), - ], - - [ - 'QuoteAsset', - new beet.BeetArgsStruct( - [['quoteAmount', beet.u64]], - 'FixedSizeRecord["QuoteAsset"]' - ), - ], - ]) as beet.FixableBeet; - const fixedSizeSerializer = createSerializerFromFixableBeet(fixedSizeBeet); return fixedSizeSerializer.serialize(fixedSize); @@ -224,6 +167,8 @@ type RfqInput = { /** The SHA256 hash of the serialized legs of the RFQ. */ legsHash: Buffer; + printTradeProvider: PublicKey | null; + /** The order type of the Rfq. */ orderType: OrderType; @@ -247,7 +192,7 @@ type RfqInput = { settlingWindow: number; /** A recent timestamp. */ - recentTimestamp: anchor.BN; + recentTimestamp: BN; // recentTimestamp: number; }; diff --git a/packages/js/src/plugins/rfqModule/helpers.ts b/packages/js/src/plugins/rfqModule/helpers.ts index 0fa5c3608..57a3771b1 100644 --- a/packages/js/src/plugins/rfqModule/helpers.ts +++ b/packages/js/src/plugins/rfqModule/helpers.ts @@ -1,4 +1,4 @@ -import { AccountMeta } from '@solana/web3.js'; +import { AccountMeta, PublicKey } from '@solana/web3.js'; import { Sha256 } from '@aws-crypto/sha256-js'; import { ApiLeg } from '@convergence-rfq/rfq'; import { @@ -12,13 +12,11 @@ import { UnparsedAccount } from '../../types'; import { Convergence } from '../../Convergence'; import { LegInstrument, - getSerializedLegLength, getValidationAccounts, - serializeAsLeg, - toLeg, + instrumentToSolitaLeg, } from '../instrumentModule'; +import { Rfq, Response, AuthoritySide, isFixedSizeOpen } from './models'; import { LEG_MULTIPLIER_DECIMALS } from './constants'; -import { Rfq, Response, isFixedSizeOpen } from './models'; export function getPages( accounts: T[], @@ -52,18 +50,11 @@ export function getPages( } export const calculateExpectedLegsHash = ( - instruments: LegInstrument[] + serializedLegs: Buffer[] ): Uint8Array => { - const serializedLegsData: Buffer[] = instruments.map((i) => - serializeAsLeg(i) - ); - const lengthBuffer = Buffer.alloc(4); - lengthBuffer.writeInt32LE(instruments.length); - const fullLegDataBuffer = Buffer.concat([ - lengthBuffer, - ...serializedLegsData, - ]); + lengthBuffer.writeInt32LE(serializedLegs.length); + const fullLegDataBuffer = Buffer.concat([lengthBuffer, ...serializedLegs]); const hash = new Sha256(); hash.update(fullLegDataBuffer); @@ -72,37 +63,12 @@ export const calculateExpectedLegsHash = ( return expectedLegsHash; }; -export const calculateExpectedLegsSize = ( - instruments: LegInstrument[] -): number => { - return ( - 4 + - instruments.map((i) => getSerializedLegLength(i)).reduce((x, y) => x + y, 0) - ); -}; - -// TODO remove -export const instrumentsToLegsAndLegsSize = ( - instruments: LegInstrument[] -): [ApiLeg[], number] => { - return [ - instrumentsToLegs(instruments), - calculateExpectedLegsSize(instruments), - ]; +export const calculateExpectedLegsSize = (serializedLegs: Buffer[]): number => { + return 4 + serializedLegs.map((leg) => leg.length).reduce((x, y) => x + y, 0); }; export const instrumentsToLegs = (instruments: LegInstrument[]): ApiLeg[] => { - return instruments.map((i) => toLeg(i)); -}; - -// TODO remove -export const instrumentsToLegsAndExpectedLegsHash = ( - instruments: LegInstrument[] -): [ApiLeg[], Uint8Array] => { - return [ - instrumentsToLegs(instruments), - calculateExpectedLegsHash(instruments), - ]; + return instruments.map((i) => instrumentToSolitaLeg(i)); }; export const legsToBaseAssetAccounts = ( @@ -155,6 +121,22 @@ export const sortByActiveAndExpiry = (rfqs: Rfq[]) => { }); }; +export const getAuthoritySide = ( + user: PublicKey, + rfq: Rfq, + response: Response +): AuthoritySide | null => { + if (rfq.taker.equals(user)) { + return 'taker'; + } + + if (response.maker.equals(user)) { + return 'maker'; + } + + return null; +}; + export function extractLegsMultiplier( rfq: Rfq, quote: Quote, diff --git a/packages/js/src/plugins/rfqModule/models/Response.ts b/packages/js/src/plugins/rfqModule/models/Response.ts index 463e802f8..d2e538c6e 100644 --- a/packages/js/src/plugins/rfqModule/models/Response.ts +++ b/packages/js/src/plugins/rfqModule/models/Response.ts @@ -14,6 +14,7 @@ import { fromSolitaStoredResponseState, } from './StoredResponseState'; import { fromSolitaQuote, Quote } from './Quote'; +import { Rfq, isSettledAsPrintTrade } from './Rfq'; /** * This model captures all the relevant information about a response @@ -21,10 +22,7 @@ import { fromSolitaQuote, Quote } from './Quote'; * * @group Models */ -export type Response = { - /** A model identifier to distinguish models in the SDK. */ - readonly model: 'response'; - +type CommonResponse = { /** The address of the response. */ readonly address: PublicKey; @@ -55,6 +53,19 @@ export type Response = { /** The current state of the response. */ readonly state: StoredResponseState; + // TODO: Should be a ResponseSide? + /** The optional confirmation of this response. */ + readonly confirmed: Confirmation | null; + + // + /** The optional defaulting party of this response. */ + readonly defaultingParty: SolitaDefaultingParty | null; +}; + +export type EscrowResponse = CommonResponse & { + /** A model identifier to distinguish models in the SDK. */ + readonly model: 'escrowResponse'; + /** The number of legs prepared by the taker. */ readonly takerPreparedLegs: number; @@ -64,21 +75,32 @@ export type Response = { /** The number of legs that have already been settled. */ readonly settledLegs: number; - // TODO: Should be a ResponseSide? - /** The optional confirmation of this response. */ - readonly confirmed: Confirmation | null; - - // - /** The optional defaulting party of this response. */ - readonly defaultingParty: SolitaDefaultingParty | null; - /** Shows whether the maker or taker initialized preparation for each prepared leg. */ readonly legPreparationsInitializedBy: AuthoritySide[]; }; +export type PrintTradeResponse = CommonResponse & { + /** A model identifier to distinguish models in the SDK. */ + readonly model: 'printTradeResponse'; + + /** The number of legs prepared by the taker. */ + readonly takerPrepared: boolean; + + /** The number of legs prepared by the maker. */ + readonly makerPrepared: boolean; + + /** Shows whether the maker or taker initialized the print trade. */ + readonly printTradeInitializedBy: AuthoritySide | null; + + readonly additionalData: Uint8Array; +}; + +export type Response = EscrowResponse | PrintTradeResponse; + /** @group Model Helpers */ export const isResponse = (value: any): value is Response => - typeof value === 'object' && value.model === 'response'; + typeof value === 'object' && + (value.model === 'escrowResponse' || value.model === 'printTradeResponse'); /** @group Model Helpers */ export function assertResponse(value: any): asserts value is Response { @@ -89,39 +111,65 @@ export function assertResponse(value: any): asserts value is Response { export const toResponse = ( account: ResponseAccount, collateralDecimals: number, - quoteDecimals: number -): Response => ({ - model: 'response', - address: account.publicKey, - maker: account.data.maker, - rfq: account.data.rfq, - creationTimestamp: convertTimestampToMilliSeconds( - account.data.creationTimestamp - ), - expirationTimestamp: convertTimestampToMilliSeconds( - account.data.expirationTimestamp - ), - makerCollateralLocked: removeDecimals( - account.data.makerCollateralLocked, - collateralDecimals - ), - takerCollateralLocked: removeDecimals( - account.data.takerCollateralLocked, - collateralDecimals - ), - state: fromSolitaStoredResponseState(account.data.state), - // TODO: Abstract with response model method - takerPreparedLegs: account.data.takerPreparedLegs, - // TODO: Abstract with response model method - makerPreparedLegs: account.data.makerPreparedLegs, - // TODO: Abstract with response model method - settledLegs: account.data.settledLegs, - confirmed: - account.data.confirmed && fromSolitaConfirmation(account.data.confirmed), - defaultingParty: account.data.defaultingParty, - legPreparationsInitializedBy: account.data.legPreparationsInitializedBy.map( - fromSolitaAuthoritySide - ), - bid: account.data.bid && fromSolitaQuote(account.data.bid, quoteDecimals), - ask: account.data.ask && fromSolitaQuote(account.data.ask, quoteDecimals), -}); + rfq: Rfq +): Response => { + if (!rfq.address.equals(account.data.rfq)) { + throw new Error('Passed rfq does not match the one stored in response'); + } + + const commonResponse: CommonResponse = { + address: account.publicKey, + maker: account.data.maker, + rfq: account.data.rfq, + creationTimestamp: convertTimestampToMilliSeconds( + account.data.creationTimestamp + ), + expirationTimestamp: convertTimestampToMilliSeconds( + account.data.expirationTimestamp + ), + makerCollateralLocked: removeDecimals( + account.data.makerCollateralLocked, + collateralDecimals + ), + takerCollateralLocked: removeDecimals( + account.data.takerCollateralLocked, + collateralDecimals + ), + state: fromSolitaStoredResponseState(account.data.state), + bid: + account.data.bid && + fromSolitaQuote(account.data.bid, rfq.quoteAsset.getDecimals()), + ask: + account.data.ask && + fromSolitaQuote(account.data.ask, rfq.quoteAsset.getDecimals()), + confirmed: + account.data.confirmed && fromSolitaConfirmation(account.data.confirmed), + defaultingParty: account.data.defaultingParty, + }; + + if (isSettledAsPrintTrade(rfq)) { + return { + model: 'printTradeResponse', + ...commonResponse, + takerPrepared: account.data.takerPreparedCounter > 0, + makerPrepared: account.data.makerPreparedCounter > 0, + printTradeInitializedBy: + account.data.printTradeInitializedBy !== null + ? fromSolitaAuthoritySide(account.data.printTradeInitializedBy) + : null, + additionalData: account.data.additionalData, + }; + } + + return { + model: 'escrowResponse', + ...commonResponse, + takerPreparedLegs: account.data.takerPreparedCounter, + makerPreparedLegs: account.data.makerPreparedCounter, + settledLegs: account.data.settledEscrowLegs, + legPreparationsInitializedBy: + account.data.escrowLegPreparationsInitializedBy.map( + fromSolitaAuthoritySide + ), + }; +}; diff --git a/packages/js/src/plugins/rfqModule/models/Rfq.ts b/packages/js/src/plugins/rfqModule/models/Rfq.ts index d7275e993..3df2c9ad3 100644 --- a/packages/js/src/plugins/rfqModule/models/Rfq.ts +++ b/packages/js/src/plugins/rfqModule/models/Rfq.ts @@ -18,6 +18,11 @@ import { collateralMintCache } from '../../../plugins/collateralModule'; import { FixedSize, fromSolitaFixedSize } from './FixedSize'; import { OrderType, fromSolitaOrderType } from './OrderType'; import { StoredRfqState, fromSolitaStoredRfqState } from './StoredRfqState'; +import { + PrintTrade, + PrintTradeLeg, + PrintTradeQuote, +} from '@/plugins/printTradeModule'; /** * This model captures all the relevant information about an RFQ @@ -25,10 +30,7 @@ import { StoredRfqState, fromSolitaStoredRfqState } from './StoredRfqState'; * * @group Models */ -export type Rfq = { - /** A model identifier to distinguish models in the SDK. */ - readonly model: 'rfq'; - +type CommonRfq = { /** The address of the Rfq. */ readonly address: PublicKey; @@ -42,12 +44,6 @@ export type Rfq = { * or a fixed amount of the quote asset. */ readonly size: FixedSize; - /** The quote asset of the Rfq. */ - readonly quoteAsset: QuoteInstrument; - - /** The quote asset mint. */ - readonly quoteMint: PublicKey; - /** The time at which this Rfq was created. */ readonly creationTimestamp: number; @@ -85,41 +81,83 @@ export type Rfq = { /** The address of the Whitelist. */ readonly whitelist: PublicKey; +}; + +export type EscrowRfq = CommonRfq & { + /** A model identifier to distinguish models in the SDK. */ + readonly model: 'escrowRfq'; + + /** The quote asset of the Rfq. */ + readonly quoteAsset: QuoteInstrument; + + /** The quote asset mint. */ + readonly quoteMint: PublicKey; /** The legs of the Rfq. */ readonly legs: LegInstrument[]; }; +export type PrintTradeRfq = CommonRfq & { + /** A model identifier to distinguish models in the SDK. */ + readonly model: 'printTradeRfq'; + + /** A model that stores legs, quote info and a settlement venue. */ + readonly printTrade: PrintTrade; + + /** The quote asset of the Rfq. */ + readonly quoteAsset: PrintTradeQuote; + + /** The legs of the Rfq. */ + readonly legs: PrintTradeLeg[]; +}; + +export type Rfq = EscrowRfq | PrintTradeRfq; + /** @group Model Helpers */ -export const isRfq = (value: any): value is Rfq => - typeof value === 'object' && value.model === 'rfq'; +export const isEscrowRfq = (value: any): value is Rfq => + typeof value === 'object' && value.model === 'escrowRfq'; + +export const isPrintTradeRfq = (value: any): value is Rfq => + typeof value === 'object' && value.model === 'printTradeRfq'; /** @group Model Helpers */ export function assertRfq(value: any): asserts value is Rfq { - assert(isRfq(value), 'Expected Rfq model'); + assert(isEscrowRfq(value) || isPrintTradeRfq(value), 'Expected Rfq model'); +} + +export function assertEscrowRfq(value: any): asserts value is EscrowRfq { + assert(isEscrowRfq(value), 'Expected Escrow Rfq model'); +} + +export function assertPrintTradeRfq( + value: any +): asserts value is PrintTradeRfq { + assert(isPrintTradeRfq(value), 'Expected Print Trade Rfq model'); +} + +export function isSettledAsPrintTrade(rfq: Rfq): boolean { + return rfq.model === 'printTradeRfq'; } /** @group Model Helpers */ export const toRfq = async ( - convergence: Convergence, + cvg: Convergence, account: RfqAccount ): Promise => { + const protocol = await cvg.protocol().get(); const quoteAsset = await SpotQuoteInstrument.parseFromQuote( - convergence, + cvg, + protocol, account.data.quoteAsset ); - const collateralMint = await collateralMintCache.get(convergence); + const collateralMint = await collateralMintCache.get(cvg); const collateralDecimals = collateralMint.decimals; - return { - model: 'rfq', + + const commonRfq: CommonRfq = { address: account.publicKey, taker: account.data.taker, orderType: fromSolitaOrderType(account.data.orderType), size: fromSolitaFixedSize(account.data.fixedSize, quoteAsset.getDecimals()), - quoteAsset, - quoteMint: SpotLegInstrument.deserializeInstrumentData( - Buffer.from(account.data.quoteAsset.instrumentData) - ).mintAddress, creationTimestamp: convertTimestampToMilliSeconds( account.data.creationTimestamp ), @@ -139,6 +177,32 @@ export const toRfq = async ( clearedResponses: account.data.clearedResponses, confirmedResponses: account.data.confirmedResponses, whitelist: account.data.whitelist, - legs: account.data.legs.map((leg) => convergence.parseLegInstrument(leg)), + }; + + if (account.data.printTradeProvider === null) { + return { + model: 'escrowRfq', + ...commonRfq, + quoteAsset, + quoteMint: SpotLegInstrument.deserializeInstrumentData( + Buffer.from(account.data.quoteAsset.data) + ).mintAddress, + legs: account.data.legs.map((leg) => + cvg.parseLegInstrument(leg, protocol) + ), + }; + } + + const printTrade = cvg.parsePrintTrade( + account.data.printTradeProvider, + account.data.legs, + account.data.quoteAsset + ); + return { + model: 'printTradeRfq', + ...commonRfq, + printTrade, + legs: printTrade.getLegs(), + quoteAsset: printTrade.getQuote(), }; }; diff --git a/packages/js/src/plugins/rfqModule/models/StoredResponseState.ts b/packages/js/src/plugins/rfqModule/models/StoredResponseState.ts index 82c2c6d8d..380547130 100644 --- a/packages/js/src/plugins/rfqModule/models/StoredResponseState.ts +++ b/packages/js/src/plugins/rfqModule/models/StoredResponseState.ts @@ -7,9 +7,12 @@ export type StoredResponseState = | 'ready-for-settling' | 'settled' | 'settling-preparations' - | 'waiting-for-last-look' + | 'settlement-expired' + | 'waiting-for-last-look'; -export function fromSolitaStoredResponseState(StoredResponseState: SolitaStoredResponseState): StoredResponseState { +export function fromSolitaStoredResponseState( + StoredResponseState: SolitaStoredResponseState +): StoredResponseState { switch (StoredResponseState) { case SolitaStoredResponseState.Active: { return 'active'; @@ -29,13 +32,18 @@ export function fromSolitaStoredResponseState(StoredResponseState: SolitaStoredR case SolitaStoredResponseState.SettlingPreparations: { return 'settling-preparations'; } + case SolitaStoredResponseState.SettlementExpired: { + return 'settlement-expired'; + } case SolitaStoredResponseState.WaitingForLastLook: { return 'waiting-for-last-look'; } } } -export function toSolitaStoredResponseState(StoredResponseState: StoredResponseState): SolitaStoredResponseState { +export function toSolitaStoredResponseState( + StoredResponseState: StoredResponseState +): SolitaStoredResponseState { switch (StoredResponseState) { case 'active': { return SolitaStoredResponseState.Active; @@ -55,6 +63,9 @@ export function toSolitaStoredResponseState(StoredResponseState: StoredResponseS case 'settling-preparations': { return SolitaStoredResponseState.SettlingPreparations; } + case 'settlement-expired': { + return SolitaStoredResponseState.SettlementExpired; + } case 'waiting-for-last-look': { return SolitaStoredResponseState.WaitingForLastLook; } diff --git a/packages/js/src/plugins/rfqModule/models/StoredRfqState.ts b/packages/js/src/plugins/rfqModule/models/StoredRfqState.ts index 0062f7716..ab6ff5440 100644 --- a/packages/js/src/plugins/rfqModule/models/StoredRfqState.ts +++ b/packages/js/src/plugins/rfqModule/models/StoredRfqState.ts @@ -1,10 +1,15 @@ import { StoredRfqState as SolitaStoredRfqState } from '@convergence-rfq/rfq'; type Constructed = 'constructed'; +type ValidatedByPrintTradeProvider = 'validated-by-print-trade-provider'; type Active = 'active'; type Canceled = 'canceled'; -export type StoredRfqState = Constructed | Active | Canceled; +export type StoredRfqState = + | Constructed + | ValidatedByPrintTradeProvider + | Active + | Canceled; export function fromSolitaStoredRfqState( state: SolitaStoredRfqState @@ -13,6 +18,9 @@ export function fromSolitaStoredRfqState( case SolitaStoredRfqState.Constructed: { return 'constructed'; } + case SolitaStoredRfqState.ValidatedByPrintTradeProvider: { + return 'validated-by-print-trade-provider'; + } case SolitaStoredRfqState.Active: { return 'active'; } @@ -29,6 +37,9 @@ export function toSolitaStoredRfqState( case 'constructed': { return SolitaStoredRfqState.Constructed; } + case 'validated-by-print-trade-provider': { + return SolitaStoredRfqState.ValidatedByPrintTradeProvider; + } case 'active': { return SolitaStoredRfqState.Active; } diff --git a/packages/js/src/plugins/rfqModule/operations/addLegsToRfq.ts b/packages/js/src/plugins/rfqModule/operations/addLegsToRfq.ts index 6f65ae26c..b5499f9dc 100644 --- a/packages/js/src/plugins/rfqModule/operations/addLegsToRfq.ts +++ b/packages/js/src/plugins/rfqModule/operations/addLegsToRfq.ts @@ -1,8 +1,12 @@ import { createAddLegsToRfqInstruction } from '@convergence-rfq/rfq'; -import { PublicKey, AccountMeta } from '@solana/web3.js'; +import { PublicKey } from '@solana/web3.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { instrumentsToLegAccounts, instrumentsToLegs } from '../helpers'; +import { + instrumentsToLegAccounts, + instrumentsToLegs, + legsToBaseAssetAccounts, +} from '../helpers'; import { Convergence } from '../../../Convergence'; import { Operation, @@ -136,23 +140,7 @@ export const addLegsToRfqBuilder = async ( const legs = instrumentsToLegs(instruments); const legAccounts = await instrumentsToLegAccounts(instruments); - const baseAssetAccounts: AccountMeta[] = []; - const baseAssetIndexValues = []; - for (const leg of legs) { - baseAssetIndexValues.push(leg.baseAssetIndex.value); - } - - for (const value of baseAssetIndexValues) { - const baseAsset = convergence.protocol().pdas().baseAsset({ index: value }); - - const baseAssetAccount: AccountMeta = { - pubkey: baseAsset, - isSigner: false, - isWritable: false, - }; - - baseAssetAccounts.push(baseAssetAccount); - } + const baseAssetAccounts = legsToBaseAssetAccounts(convergence, legs); const rfqProgram = convergence.programs().getRfq(programs); diff --git a/packages/js/src/plugins/rfqModule/operations/cleanUpResponse.ts b/packages/js/src/plugins/rfqModule/operations/cleanUpResponse.ts index 59c4de375..c8d0ac84b 100644 --- a/packages/js/src/plugins/rfqModule/operations/cleanUpResponse.ts +++ b/packages/js/src/plugins/rfqModule/operations/cleanUpResponse.ts @@ -11,8 +11,15 @@ import { } from '../../../types'; import { TransactionBuilder, TransactionBuilderOptions } from '../../../utils'; import { InstrumentPdasClient } from '../../instrumentModule/InstrumentPdasClient'; +import { + EscrowResponse, + EscrowRfq, + PrintTradeResponse, + PrintTradeRfq, +} from '../models'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; -import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { SendAndConfirmTransactionResponse } from '@/plugins/rpcModule'; +import { prependWithProviderProgram } from '@/plugins/printTradeModule'; const Key = 'cleanUpResponseOperation' as const; @@ -54,18 +61,6 @@ export type CleanUpResponseInput = { * The address of the reponse accounts. */ response: PublicKey; - - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** - * The maker public key address. - */ - maker: PublicKey; }; /** @@ -127,22 +122,75 @@ export const cleanUpResponseBuilder = async ( convergence: Convergence, params: CleanUpResponseBuilderParams, options: TransactionBuilderOptions = {} +): Promise => { + const responseModel = await convergence + .rfqs() + .findResponseByAddress({ address: params.response }); + const rfqModel = await convergence + .rfqs() + .findRfqByAddress({ address: responseModel.rfq }); + + if ( + responseModel.model === 'escrowResponse' && + rfqModel.model === 'escrowRfq' + ) { + return cleanUpEscrowResponseBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + }, + options + ); + } else if ( + responseModel.model === 'printTradeResponse' && + rfqModel.model === 'printTradeRfq' + ) { + return cleanUpPrintTradeResponseBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + }, + options + ); + } + + throw new Error('Rfq type does not match with response type!'); +}; + +export type CleanUpEscrowResponseBuilderParams = { + response: PublicKey | EscrowResponse; + rfq?: EscrowRfq; +}; + +export const cleanUpEscrowResponseBuilder = async ( + convergence: Convergence, + params: CleanUpEscrowResponseBuilderParams, + options: TransactionBuilderOptions = {} ) => { const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { response, maker = convergence.identity().publicKey } = params; + const { response, rfq } = params; + + const responseModel = + response instanceof PublicKey + ? await convergence.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? + (await convergence.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } const dao = convergence.identity().publicKey; const rfqProgram = convergence.programs().getRfq(programs); const anchorRemainingAccounts: AccountMeta[] = []; - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); - - const rfqModel = await convergence - .rfqs() - .findRfqByAddress({ address: responseModel.rfq }); - for (let i = 0; i < responseModel.legPreparationsInitializedBy.length; i++) { const leg = rfqModel.legs[i]; const firstToPrepare = @@ -237,7 +285,7 @@ export const cleanUpResponseBuilder = async ( .add({ instruction: createCleanUpResponseInstruction( { - maker, + maker: responseModel.maker, protocol: convergence.protocol().pdas().protocol(), rfq: responseModel.rfq, response: responseModel.address, @@ -249,3 +297,55 @@ export const cleanUpResponseBuilder = async ( key: 'cleanUpResponses', }); }; + +export type CleanUpPrintTradeResponseBuilderParams = { + response: PublicKey | PrintTradeResponse; + rfq?: PrintTradeRfq; +}; + +export const cleanUpPrintTradeResponseBuilder = async ( + convergence: Convergence, + params: CleanUpPrintTradeResponseBuilderParams, + options: TransactionBuilderOptions = {} +) => { + const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; + const { response, rfq } = params; + + const responseModel = + response instanceof PublicKey + ? await convergence.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? + (await convergence.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'printTradeResponse' || + rfqModel.model !== 'printTradeRfq' + ) { + throw new Error('Response is not settled as a print trade!'); + } + + const rfqProgram = convergence.programs().getRfq(programs); + const remainingAccounts = prependWithProviderProgram( + rfqModel.printTrade, + await rfqModel.printTrade.getCleanUpAccounts(rfqModel, responseModel) + ); + + return TransactionBuilder.make() + .setFeePayer(payer) + .add({ + instruction: createCleanUpResponseInstruction( + { + maker: responseModel.maker, + protocol: convergence.protocol().pdas().protocol(), + rfq: responseModel.rfq, + response: responseModel.address, + anchorRemainingAccounts: remainingAccounts, + }, + rfqProgram.address + ), + signers: [], + key: 'cleanUpResponses', + }); +}; diff --git a/packages/js/src/plugins/rfqModule/operations/cleanUpResponseLegs.ts b/packages/js/src/plugins/rfqModule/operations/cleanUpResponseLegs.ts index c23cfb9cc..f4ce81798 100644 --- a/packages/js/src/plugins/rfqModule/operations/cleanUpResponseLegs.ts +++ b/packages/js/src/plugins/rfqModule/operations/cleanUpResponseLegs.ts @@ -1,4 +1,4 @@ -import { createCleanUpResponseLegsInstruction } from '@convergence-rfq/rfq'; +import { createCleanUpResponseEscrowLegsInstruction } from '@convergence-rfq/rfq'; import { PublicKey, AccountMeta } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; @@ -158,6 +158,13 @@ export const cleanUpResponseLegsBuilder = async ( .rfqs() .findResponseByAddress({ address: response }); + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } + const initializedLegs = responseModel.legPreparationsInitializedBy.length; const anchorRemainingAccounts: AccountMeta[] = []; for (let i = initializedLegs - legAmountToClear; i < initializedLegs; i++) { @@ -208,7 +215,7 @@ export const cleanUpResponseLegsBuilder = async ( .setFeePayer(payer) .addTxPriorityFeeIx(convergence) .add({ - instruction: createCleanUpResponseLegsInstruction( + instruction: createCleanUpResponseEscrowLegsInstruction( { protocol: protocol.address, rfq, diff --git a/packages/js/src/plugins/rfqModule/operations/confirmResponse.ts b/packages/js/src/plugins/rfqModule/operations/confirmResponse.ts index 9bc5b9ab7..3aae5831b 100644 --- a/packages/js/src/plugins/rfqModule/operations/confirmResponse.ts +++ b/packages/js/src/plugins/rfqModule/operations/confirmResponse.ts @@ -1,5 +1,5 @@ import { createConfirmResponseInstruction } from '@convergence-rfq/rfq'; -import { PublicKey, AccountMeta, ComputeBudgetProgram } from '@solana/web3.js'; +import { PublicKey, ComputeBudgetProgram } from '@solana/web3.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; import { Convergence } from '../../../Convergence'; @@ -17,6 +17,7 @@ import { import { Response } from '../models'; import { ResponseSide, toSolitaQuoteSide } from '../models/ResponseSide'; import { toSolitaOverrideLegMultiplierBps } from '../models/Confirmation'; +import { getRiskEngineAccounts } from '@/plugins/riskEngineModule/helpers'; const Key = 'ConfirmResponseOperation' as const; @@ -200,75 +201,44 @@ export const confirmResponseBuilder = async ( programs, }); - const baseAssetIndexValuesSet: Set = new Set(); const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - for (const leg of rfqModel.legs) { - baseAssetIndexValuesSet.add(leg.getBaseAssetIndex().value); - } - - const baseAssetAccounts: AccountMeta[] = []; - const oracleAccounts: AccountMeta[] = []; - const baseAssetIndexValues = Array.from(baseAssetIndexValuesSet); - for (const index of baseAssetIndexValues) { - const baseAsset = convergence.protocol().pdas().baseAsset({ index }); - baseAssetAccounts.push({ - pubkey: baseAsset, - isSigner: false, - isWritable: false, - }); - - const baseAssetModel = await convergence - .protocol() - .findBaseAssetByAddress({ address: baseAsset }); - - if (baseAssetModel.priceOracle.address) { - oracleAccounts.push({ - pubkey: baseAssetModel.priceOracle.address, - isSigner: false, - isWritable: false, - }); - } - } + const riskEngineAccounts = await getRiskEngineAccounts( + convergence, + rfqModel.legs + ); return TransactionBuilder.make() .setFeePayer(payer) - .add({ - instruction: ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_400_000, - }), - signers: [], - }) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createConfirmResponseInstruction( - { - rfq, - response, - collateralInfo, - makerCollateralInfo, - collateralToken, - taker: taker.publicKey, - protocol: convergence.protocol().pdas().protocol(), - riskEngine: convergence.programs().getRiskEngine(programs).address, - anchorRemainingAccounts: [ - { - pubkey: convergence.riskEngine().pdas().config(), - isSigner: false, - isWritable: false, - }, - ...baseAssetAccounts, - ...oracleAccounts, - ], - }, - { - side: toSolitaQuoteSide(side), - overrideLegMultiplierBps, - }, - convergence.programs().getRfq(programs).address - ), - signers: [taker], - key: 'confirmResponse', - }); + .add( + { + instruction: ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_400_000, + }), + signers: [], + }, + { + instruction: createConfirmResponseInstruction( + { + rfq, + response, + collateralInfo, + makerCollateralInfo, + collateralToken, + taker: taker.publicKey, + protocol: convergence.protocol().pdas().protocol(), + riskEngine: convergence.programs().getRiskEngine(programs).address, + anchorRemainingAccounts: riskEngineAccounts, + }, + { + side: toSolitaQuoteSide(side), + overrideLegMultiplierBps, + }, + convergence.programs().getRfq(programs).address + ), + signers: [taker], + key: 'confirmResponse', + } + ); }; const isResponseExpired = (response: Response): boolean => { diff --git a/packages/js/src/plugins/rfqModule/operations/createAndFinalizeRfqConstruction.ts b/packages/js/src/plugins/rfqModule/operations/createAndFinalizeRfqConstruction.ts index ab61f81c9..b9ccceb58 100644 --- a/packages/js/src/plugins/rfqModule/operations/createAndFinalizeRfqConstruction.ts +++ b/packages/js/src/plugins/rfqModule/operations/createAndFinalizeRfqConstruction.ts @@ -1,5 +1,5 @@ import { Keypair, PublicKey } from '@solana/web3.js'; -import * as anchor from '@project-serum/anchor'; +import * as anchor from '@coral-xyz/anchor'; import { BN } from 'bn.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; @@ -22,7 +22,8 @@ import { import { LegInstrument, QuoteInstrument, - toQuote, + serializeInstrumentAsSolitaLeg, + instrumentToQuote, } from '../../../plugins/instrumentModule'; import { OrderType } from '../models/OrderType'; import { createRfqBuilder } from './createRfq'; @@ -186,6 +187,7 @@ export const createAndFinalizeRfqConstructionOperationHandler: OperationHandler< } const payer = convergence.rpc().getDefaultFeePayer(); const recentTimestamp = new BN(Math.floor(Date.now() / 1_000)); + const rfqPreparationTxBuilderArray: TransactionBuilder[] = []; const ixTracker = new InstructionUniquenessTracker([]); for (const ins of instruments) { @@ -206,7 +208,10 @@ export const createAndFinalizeRfqConstructionOperationHandler: OperationHandler< if (rfqPreparationTxBuilder.getInstructionCount() > 0) rfqPreparationTxBuilderArray.push(rfqPreparationTxBuilder); } - const expectedLegsHash = calculateExpectedLegsHash(instruments); + const serializedLegs = instruments.map((instruments) => + serializeInstrumentAsSolitaLeg(instruments) + ); + const expectedLegsHash = calculateExpectedLegsHash(serializedLegs); const rfqPda = convergence .rfqs() @@ -214,8 +219,9 @@ export const createAndFinalizeRfqConstructionOperationHandler: OperationHandler< .rfq({ taker: taker.publicKey, legsHash: Buffer.from(expectedLegsHash), + printTradeProvider: null, orderType, - quoteAsset: toQuote(quoteAsset), + quoteAsset: instrumentToQuote(quoteAsset), fixedSize, activeWindow, settlingWindow, diff --git a/packages/js/src/plugins/rfqModule/operations/createPrintTradeRfq.ts b/packages/js/src/plugins/rfqModule/operations/createPrintTradeRfq.ts new file mode 100644 index 000000000..eba0815a2 --- /dev/null +++ b/packages/js/src/plugins/rfqModule/operations/createPrintTradeRfq.ts @@ -0,0 +1,406 @@ +import { + createCreateRfqInstruction, + createValidateRfqByPrintTradeProviderInstruction, +} from '@convergence-rfq/rfq'; +import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; +import * as anchor from '@coral-xyz/anchor'; + +import { BN } from 'bn.js'; +import { SendAndConfirmTransactionResponse } from '../../rpcModule'; +import { + assertPrintTradeRfq, + FixedSize, + PrintTradeRfq, + toSolitaFixedSize, +} from '../models'; +import { + calculateExpectedLegsHash, + calculateExpectedLegsSize, + legsToBaseAssetAccounts, +} from '../helpers'; +import { + TransactionBuilder, + TransactionBuilderOptions, +} from '../../../utils/TransactionBuilder'; +import { + makeConfirmOptionsFinalizedOnMainnet, + Operation, + OperationHandler, + OperationScope, + useOperation, + Signer, +} from '../../../types'; +import { Convergence } from '../../../Convergence'; +import { OrderType, toSolitaOrderType } from '../models/OrderType'; +import { finalizeRfqConstructionBuilder } from './finalizeRfqConstruction'; +import { + PrintTrade, + serializePrintTradeAsSolitaLeg, + printTradeToSolitaLeg, + printTradetoSolitaQuote, + prependWithProviderProgram, +} from '@/plugins/printTradeModule'; +import { createWhitelistBuilder } from '@/plugins/whitelistModule'; + +const Key = 'CreatePrintTradeRfqOperation' as const; + +export const createPrintTradeRfqOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type CreatePrintTradeRfqOperation = Operation< + typeof Key, + CreatePrintTradeRfqInput, + CreatePrintTradeRfqOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type CreatePrintTradeRfqInput = { + /** + * The taker of the Rfq to create. + * + * @defaultValue `convergence.identity().publicKey` + */ + taker?: Signer; + + printTrade: PrintTrade; + + /** The type of order. */ + orderType: OrderType; + + /** + * The type of the Rfq, specifying whether we fix the number of + * base assets to be exchanged, the number of quote assets, + * or neither. + */ + fixedSize: FixedSize; + + /** + * Active window (in seconds). + */ + activeWindow: number; + + /** + * Settling window (in seconds). + */ + settlingWindow: number; + + /** Optional counterparties PubkeyList to create a whitelist. */ + counterParties?: PublicKey[]; +}; + +/** + * @group Operations + * @category Outputs + */ +export type CreatePrintTradeRfqOutput = { + /** The blockchain response from sending and confirming the transaction. */ + response: SendAndConfirmTransactionResponse; + + /** The newly created Rfq. */ + rfq: PrintTradeRfq; +}; + +/** + * @group Operations + * @category Handlers + */ +export const createPrintTradeRfqOperationHandler: OperationHandler = + { + handle: async ( + operation: CreatePrintTradeRfqOperation, + convergence: Convergence, + scope: OperationScope + ) => { + const { + taker = convergence.identity(), + orderType, + printTrade, + fixedSize, + activeWindow, + settlingWindow, + counterParties = [], + } = operation.input; + const recentTimestamp = new BN(Math.floor(Date.now() / 1_000)); + const serializedLegs = printTrade + .getLegs() + .map((leg) => serializePrintTradeAsSolitaLeg(leg)); + const expectedLegsHash = calculateExpectedLegsHash(serializedLegs); + let createWhitelistTxBuilder: TransactionBuilder | null = null; + let whitelistAccount = null; + if (counterParties.length > 0) { + whitelistAccount = Keypair.generate(); + createWhitelistTxBuilder = await createWhitelistBuilder( + convergence, + { + creator: taker.publicKey, + whitelist: counterParties, + whitelistKeypair: whitelistAccount, + }, + scope + ); + } + const rfqPda = convergence + .rfqs() + .pdas() + .rfq({ + taker: taker.publicKey, + legsHash: Buffer.from(expectedLegsHash), + printTradeProvider: printTrade.getPrintTradeProviderProgramId(), + orderType, + quoteAsset: printTradetoSolitaQuote(printTrade.getQuote()), + fixedSize, + activeWindow, + settlingWindow, + recentTimestamp, + }); + + const createPrintTradeRfqBuilder = + await createPrintTradeFullFlowRfqBuilder( + convergence, + { + ...operation.input, + rfq: rfqPda, + fixedSize, + activeWindow, + settlingWindow, + expectedLegsHash, + recentTimestamp, + whitelistAccount: whitelistAccount + ? whitelistAccount.publicKey + : null, + }, + scope + ); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + convergence, + scope.confirmOptions + ); + const txs: Transaction[] = []; + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + + if (whitelistAccount && createWhitelistTxBuilder) { + const createWhitelistTx = + createWhitelistTxBuilder.toTransaction(lastValidBlockHeight); + txs.push(createWhitelistTx); + } + txs.push(createPrintTradeRfqBuilder.toTransaction(lastValidBlockHeight)); + + const signedTxs = await convergence.identity().signAllTransactions(txs); + if (whitelistAccount) { + if (signedTxs.length === 2) { + const whitelistkeypairSignedCreateWhitelistTx = await convergence + .rpc() + .signTransaction(signedTxs[0], [whitelistAccount as Signer]); + signedTxs[0] = whitelistkeypairSignedCreateWhitelistTx; + } + } + let response: SendAndConfirmTransactionResponse; + switch (signedTxs.length) { + case 1: + response = await convergence + .rpc() + .serializeAndSendTransaction( + signedTxs[0], + lastValidBlockHeight, + confirmOptions + ); + break; + case 2: + await convergence + .rpc() + .serializeAndSendTransaction( + signedTxs[0], + lastValidBlockHeight, + confirmOptions + ); + response = await convergence + .rpc() + .serializeAndSendTransaction( + signedTxs[1], + lastValidBlockHeight, + confirmOptions + ); + break; + default: + throw new Error('Unexpected number of transactions'); + } + + scope.throwIfCanceled(); + + const rfq = await convergence + .rfqs() + .findRfqByAddress({ address: rfqPda }); + assertPrintTradeRfq(rfq); + + return { response, rfq }; + }, + }; + +/** + * @group Transaction Builders + * @category Inputs + */ +export type CreatePrintTradeRfqBuilderParams = CreatePrintTradeRfqInput & { + rfq: PublicKey; + + expectedLegsHash: Uint8Array; + + recentTimestamp: anchor.BN; + + whitelistAccount: PublicKey | null; +}; + +export const createPrintTradeFullFlowRfqBuilder = async ( + convergence: Convergence, + params: CreatePrintTradeRfqBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { payer = convergence.rpc().getDefaultFeePayer() } = options; + const { rfq, printTrade } = params; + + const createRfqBuilder = await createPrintTradeRfqBuilder( + convergence, + params, + options + ); + const validatePrintTradeBuilder = + await validateRfqByPrintTradeProviderBuilder(convergence, params, options); + const finalizeRfqConstruction = await finalizeRfqConstructionBuilder( + convergence, + { ...params, legs: printTrade.getLegs() }, + options + ); + + return TransactionBuilder.make() + .setContext({ + rfq, + }) + .setFeePayer(payer) + .add(createRfqBuilder, validatePrintTradeBuilder, finalizeRfqConstruction); +}; + +/** + * Creates a new Rfq. + * + * ```ts + * const transactionBuilder = await convergence + * .rfqs() + * .builders() + * .create({}); + * ``` + * + * @group Transaction Builders + * @category Constructors + */ +export const createPrintTradeRfqBuilder = async ( + convergence: Convergence, + params: CreatePrintTradeRfqBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; + + const { + taker = convergence.identity(), + printTrade, + rfq, + orderType, + fixedSize, + activeWindow, + settlingWindow, + recentTimestamp, + expectedLegsHash, + whitelistAccount, + } = params; + + const legs = printTrade.getLegs(); + const solitaLegs = legs.map((leg) => printTradeToSolitaLeg(leg)); + const quote = printTrade.getQuote(); + const serializedLegs = legs.map((leg) => serializePrintTradeAsSolitaLeg(leg)); + const expectedLegsSize = calculateExpectedLegsSize(serializedLegs); + + const systemProgram = convergence.programs().getSystem(programs); + const rfqProgram = convergence.programs().getRfq(programs); + + const baseAssetAccounts = legsToBaseAssetAccounts(convergence, solitaLegs); + let whitelistAccountToPass = rfqProgram.address; + if (whitelistAccount) { + whitelistAccountToPass = whitelistAccount; + } + return TransactionBuilder.make() + .setFeePayer(payer) + .setContext({ + rfq, + }) + .add({ + instruction: createCreateRfqInstruction( + { + taker: taker.publicKey, + protocol: convergence.protocol().pdas().protocol(), + rfq, + systemProgram: systemProgram.address, + whitelist: whitelistAccountToPass, + anchorRemainingAccounts: [...baseAssetAccounts], + }, + { + printTradeProvider: printTrade.getPrintTradeProviderProgramId(), + expectedLegsSize, + expectedLegsHash: Array.from(expectedLegsHash), + legs: solitaLegs, + orderType: toSolitaOrderType(orderType), + quoteAsset: printTradetoSolitaQuote(quote), + fixedSize: toSolitaFixedSize(fixedSize, quote.getDecimals()), + activeWindow, + settlingWindow, + recentTimestamp, + }, + rfqProgram.address + ), + signers: [taker], + key: 'createRfq', + }); +}; + +export const validateRfqByPrintTradeProviderBuilder = async ( + convergence: Convergence, + params: CreatePrintTradeRfqBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; + + const { taker = convergence.identity(), printTrade, rfq } = params; + + const rfqProgram = convergence.programs().getRfq(programs); + + const validationAccounts = prependWithProviderProgram( + printTrade, + await printTrade.getValidationAccounts() + ); + + return TransactionBuilder.make() + .setFeePayer(payer) + .setContext({ + rfq, + }) + .add({ + instruction: createValidateRfqByPrintTradeProviderInstruction( + { + taker: taker.publicKey, + protocol: convergence.protocol().pdas().protocol(), + rfq, + anchorRemainingAccounts: validationAccounts, + }, + rfqProgram.address + ), + signers: [taker], + key: 'validateRfqByPrintTradeProvider', + }); +}; diff --git a/packages/js/src/plugins/rfqModule/operations/createRfq.ts b/packages/js/src/plugins/rfqModule/operations/createRfq.ts index 83b61da0e..82521f73b 100644 --- a/packages/js/src/plugins/rfqModule/operations/createRfq.ts +++ b/packages/js/src/plugins/rfqModule/operations/createRfq.ts @@ -1,6 +1,6 @@ import { createCreateRfqInstruction } from '@convergence-rfq/rfq'; import { PublicKey, AccountMeta, Keypair } from '@solana/web3.js'; -import * as anchor from '@project-serum/anchor'; +import * as anchor from '@coral-xyz/anchor'; import { BN } from 'bn.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; @@ -28,7 +28,9 @@ import { Convergence } from '../../../Convergence'; import { LegInstrument, QuoteInstrument, - toQuote, + serializeInstrumentAsSolitaLeg, + instrumentToQuote, + instrumentToSolitaLeg, } from '../../../plugins/instrumentModule'; import { OrderType, toSolitaOrderType } from '../models/OrderType'; import { InstructionUniquenessTracker } from '@/utils/classes'; @@ -167,6 +169,9 @@ export const createRfqOperationHandler: OperationHandler = { const payer = convergence.rpc().getDefaultFeePayer(); const recentTimestamp = new BN(Math.floor(Date.now() / 1_000)); let whitelistAccount = null; + const serializedLegs = instruments.map((instrument) => + serializeInstrumentAsSolitaLeg(instrument) + ); let createWhitelistTxBuilder: TransactionBuilder | null = null; if (counterParties.length > 0) { whitelistAccount = Keypair.generate(); @@ -201,7 +206,7 @@ export const createRfqOperationHandler: OperationHandler = { rfqPreparationTxBuilderArray.push(rfqPreparationTxBuilder); } expectedLegsHash = - expectedLegsHash ?? calculateExpectedLegsHash(instruments); + expectedLegsHash ?? calculateExpectedLegsHash(serializedLegs); const rfqPda = convergence .rfqs() @@ -209,8 +214,9 @@ export const createRfqOperationHandler: OperationHandler = { .rfq({ taker: taker.publicKey, legsHash: Buffer.from(expectedLegsHash), + printTradeProvider: null, orderType, - quoteAsset: toQuote(quoteAsset), + quoteAsset: instrumentToQuote(quoteAsset), fixedSize, activeWindow, settlingWindow, @@ -350,11 +356,16 @@ export const createRfqBuilder = async ( } = params; let { expectedLegsSize } = params; + const solitaLegs = instruments.map((instrument) => + instrumentToSolitaLeg(instrument) + ); + const serializedLegs = instruments.map((instrument) => + serializeInstrumentAsSolitaLeg(instrument) + ); + expectedLegsSize = + expectedLegsSize ?? calculateExpectedLegsSize(serializedLegs); const legs = instrumentsToLegs(instruments); - const expectedLegsSizeValue = calculateExpectedLegsSize(instruments); - expectedLegsSize = expectedLegsSize ?? expectedLegsSizeValue; - const systemProgram = convergence.programs().getSystem(programs); const rfqProgram = convergence.programs().getRfq(programs); const spotInstrumentProgram = convergence @@ -371,13 +382,13 @@ export const createRfqBuilder = async ( pubkey: convergence .rfqs() .pdas() - .quote({ quoteAsset: toQuote(quoteAsset) }), + .quote({ quoteAsset: instrumentToQuote(quoteAsset) }), isSigner: false, isWritable: false, }, ]; - let baseAssetAccounts = legsToBaseAssetAccounts(convergence, legs); + let baseAssetAccounts = legsToBaseAssetAccounts(convergence, solitaLegs); let legAccounts = await instrumentsToLegAccounts(instruments); let whitelistAccountToPass = rfqProgram.address; if (whitelistAccount) { @@ -404,11 +415,12 @@ export const createRfqBuilder = async ( ], }, { + printTradeProvider: null, expectedLegsSize, expectedLegsHash: Array.from(expectedLegsHash), - legs, + legs: solitaLegs, orderType: toSolitaOrderType(orderType), - quoteAsset: toQuote(quoteAsset), + quoteAsset: instrumentToQuote(quoteAsset), fixedSize: toSolitaFixedSize(fixedSize, quoteAsset.getDecimals()), activeWindow, settlingWindow, @@ -449,11 +461,12 @@ export const createRfqBuilder = async ( ], }, { + printTradeProvider: null, expectedLegsSize, expectedLegsHash: Array.from(expectedLegsHash), legs: legsToAdd, orderType: toSolitaOrderType(orderType), - quoteAsset: toQuote(quoteAsset), + quoteAsset: instrumentToQuote(quoteAsset), fixedSize: toSolitaFixedSize(fixedSize, quoteAsset.getDecimals()), activeWindow, settlingWindow, diff --git a/packages/js/src/plugins/rfqModule/operations/finalizeRfqConstruction.ts b/packages/js/src/plugins/rfqModule/operations/finalizeRfqConstruction.ts index ece1bfe6e..23ed3a7b3 100644 --- a/packages/js/src/plugins/rfqModule/operations/finalizeRfqConstruction.ts +++ b/packages/js/src/plugins/rfqModule/operations/finalizeRfqConstruction.ts @@ -1,5 +1,5 @@ import { createFinalizeRfqConstructionInstruction } from '@convergence-rfq/rfq'; -import { PublicKey, AccountMeta, ComputeBudgetProgram } from '@solana/web3.js'; +import { PublicKey, ComputeBudgetProgram } from '@solana/web3.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; import { assertRfq, Rfq } from '../models'; @@ -17,6 +17,8 @@ import { } from '../../../types'; import { Convergence } from '../../../Convergence'; import { LegInstrument } from '@/plugins/instrumentModule'; +import { getRiskEngineAccounts } from '@/plugins/riskEngineModule/helpers'; +import { PrintTradeLeg } from '@/plugins/printTradeModule'; const Key = 'FinalizeRfqConstructionOperation' as const; @@ -86,7 +88,7 @@ export type FinalizeRfqConstructionInput = { * Is passed automatically when `createAndFinalize` * is called. Else the legs are extracted from the rfq account. */ - legs?: LegInstrument[]; + legs?: LegInstrument[] | PrintTradeLeg[]; }; /** @@ -196,61 +198,10 @@ export const finalizeRfqConstructionBuilder = async ( collateralInfo = collateralInfo ?? collateralInfoPda; collateralToken = collateralToken ?? collateralTokenPda; - const anchorRemainingAccounts: AccountMeta[] = []; + const riskEngineAccounts = await getRiskEngineAccounts(convergence, legs); const protocol = convergence.protocol().pdas().protocol(); - const [config] = PublicKey.findProgramAddressSync( - [Buffer.from('config')], - riskEngineProgram.address - ); - - const configAccount: AccountMeta = { - pubkey: config, - isSigner: false, - isWritable: false, - }; - - const oracleAccounts: AccountMeta[] = []; - - const baseAssetAccounts: AccountMeta[] = []; - const baseAssetIndexValuesSet: Set = new Set(); - - for (const leg of legs) { - baseAssetIndexValuesSet.add(leg.getBaseAssetIndex().value); - } - - const baseAssetIndexValues = Array.from(baseAssetIndexValuesSet); - - for (const index of baseAssetIndexValues) { - const baseAsset = convergence.protocol().pdas().baseAsset({ index }); - const baseAssetAccount: AccountMeta = { - pubkey: baseAsset, - isSigner: false, - isWritable: false, - }; - - baseAssetAccounts.push(baseAssetAccount); - - const baseAssetModel = await convergence - .protocol() - .findBaseAssetByAddress({ address: baseAsset }); - - if (baseAssetModel.priceOracle.address) { - oracleAccounts.push({ - pubkey: baseAssetModel.priceOracle.address, - isSigner: false, - isWritable: false, - }); - } - } - - anchorRemainingAccounts.push( - configAccount, - ...baseAssetAccounts, - ...oracleAccounts - ); - return TransactionBuilder.make() .setFeePayer(payer) .setContext({ @@ -272,7 +223,7 @@ export const finalizeRfqConstructionBuilder = async ( collateralInfo, collateralToken, riskEngine, - anchorRemainingAccounts, + anchorRemainingAccounts: riskEngineAccounts, }, rfqProgram.address ), diff --git a/packages/js/src/plugins/rfqModule/operations/findResponseByAddress.ts b/packages/js/src/plugins/rfqModule/operations/findResponseByAddress.ts index 453046e51..51b3252f9 100644 --- a/packages/js/src/plugins/rfqModule/operations/findResponseByAddress.ts +++ b/packages/js/src/plugins/rfqModule/operations/findResponseByAddress.ts @@ -75,7 +75,7 @@ export const findResponseByAddressOperationHandler: OperationHandler toResponse( - responseAccount, - collateralMint.decimals, - rfq.quoteAsset.getDecimals() - )) + .then((rfq) => + toResponse(responseAccount, collateralMint.decimals, rfq) + ) ); } } diff --git a/packages/js/src/plugins/rfqModule/operations/findResponsesByRfq.ts b/packages/js/src/plugins/rfqModule/operations/findResponsesByRfq.ts index 243cd6631..cdffa3cfe 100644 --- a/packages/js/src/plugins/rfqModule/operations/findResponsesByRfq.ts +++ b/packages/js/src/plugins/rfqModule/operations/findResponsesByRfq.ts @@ -77,7 +77,7 @@ export const findResponsesByRfqOperationHandler: OperationHandler 0 || - response.takerCollateralLocked > 0 - ) - return 'UnlockCollateral'; - if ( - response.makerCollateralLocked === 0 && - response.takerCollateralLocked === 0 - ) - return 'Cleanup'; + return 'Cleanup'; case 'SettlingPreparations': case 'OnlyMakerPrepared': case 'OnlyTakerPrepared': case 'ReadyForSettling': return 'Settle'; - case 'MakerDefaulted': - case 'TakerDefaulted': - return 'Settle One Party Defaulted'; - case 'BothDefaulted': - return 'Settle Both Party Defaulted'; case 'Rejected': return null; } @@ -222,25 +200,10 @@ const getResponseAction = ( case 'OnlyTakerPrepared': case 'ReadyForSettling': return 'Settle'; - case 'MakerDefaulted': - return 'Settle One Party Defaulted'; - case 'TakerDefaulted': - return 'Settle One Party Defaulted'; - case 'BothDefaulted': - return 'Settle Both Party Defaulted'; case 'Settled': case 'Expired': case 'Cancelled': - if ( - response.takerCollateralLocked > 0 || - response.makerCollateralLocked > 0 - ) - return 'UnlockCollateral'; - if ( - response.takerCollateralLocked === 0 && - response.makerCollateralLocked === 0 - ) - return 'Cleanup'; + return 'Cleanup'; case 'Rejected': return null; } @@ -270,9 +233,17 @@ const getDefautingParty = ( }; const hasMakerPrepared = (response: Response, rfq: Rfq) => { - return response.makerPreparedLegs === rfq.legs.length; + if (response.model === 'escrowResponse') { + return response.makerPreparedLegs === rfq.legs.length; + } + + return response.makerPrepared; }; const hasTakerPrepared = (response: Response, rfq: Rfq) => { - return response.takerPreparedLegs === rfq.legs.length; + if (response.model === 'escrowResponse') { + return response.takerPreparedLegs === rfq.legs.length; + } + + return response.takerPrepared; }; diff --git a/packages/js/src/plugins/rfqModule/operations/index.ts b/packages/js/src/plugins/rfqModule/operations/index.ts index d82acb2ea..af13e8b94 100644 --- a/packages/js/src/plugins/rfqModule/operations/index.ts +++ b/packages/js/src/plugins/rfqModule/operations/index.ts @@ -8,31 +8,24 @@ export * from './cleanUpResponseLegs'; export * from './createAndFinalizeRfqConstruction'; export * from './cleanUpRfq'; export * from './confirmResponse'; +export * from './createPrintTradeRfq'; export * from './createRfq'; export * from './finalizeRfqConstruction'; export * from './findRfqByAddress'; -export * from './partiallySettleLegs'; -export * from './partiallySettleLegsAndSettle'; export * from './partlyRevertSettlementPreparation'; export * from './prepareMoreLegsSettlement'; export * from './prepareSettlement'; export * from './prepareSettlementAndPrepareMoreLegs'; +export * from './preparePrintTradeSettlement'; export * from './respondToRfq'; export * from './findRfqs'; export * from './revertSettlementPreparation'; export * from './settle'; -export * from './settleOnePartyDefault'; -export * from './settleTwoPartyDefault'; -export * from './unlockResponseCollateral'; -export * from './unlockRfqCollateral'; export * from './findResponseByAddress'; export * from './findResponsesByRfq'; export * from './findResponsesByOwner'; export * from './findResponsesByRfq'; export * from './cleanUpRfqs'; export * from './cancelRfqs'; -export * from './unlockResponseCollateral'; -export * from './unlockResponsesCollateral'; -export * from './unlockRfqsCollateral'; export * from './getSettlementResult'; export * from './getResponseStateAndAction'; diff --git a/packages/js/src/plugins/rfqModule/operations/partiallySettleLegs.ts b/packages/js/src/plugins/rfqModule/operations/partiallySettleLegs.ts deleted file mode 100644 index 2c53cf412..000000000 --- a/packages/js/src/plugins/rfqModule/operations/partiallySettleLegs.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { PublicKey, AccountMeta, ComputeBudgetProgram } from '@solana/web3.js'; -import { createPartiallySettleLegsInstruction } from '@convergence-rfq/rfq'; -import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; - -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, - makeConfirmOptionsFinalizedOnMainnet, -} from '../../../types'; -import { Convergence } from '../../../Convergence'; -import { - TransactionBuilder, - TransactionBuilderOptions, -} from '../../../utils/TransactionBuilder'; -import { InstrumentPdasClient } from '../../instrumentModule'; -import { legToBaseAssetMint } from '@/plugins/instrumentModule'; - -const Key = 'PartiallySettleLegsOperation' as const; - -/** - * Partially settles legs of an RFQ - * - * ```ts - * const rfq = await convergence - * .rfqs() - * .partiallySettleLegs({ - * rfq: rfq.address, - * response: rfqResponse.address, - * maker, - * taker, - * legAmountToSettle: 4 - * }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const partiallySettleLegsOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type PartiallySettleLegsOperation = Operation< - typeof Key, - PartiallySettleLegsInput, - PartiallySettleLegsOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type PartiallySettleLegsInput = { - /** - * The protocol address. - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The Rfq address. */ - rfq: PublicKey; - - /** The Response address. */ - response: PublicKey; - - /** The Maker's public key address. */ - maker: PublicKey; - - /** The Taker's public key address. */ - taker: PublicKey; - - /* - * Args - */ - - /** The number of legs to settle. */ - legAmountToSettle: number; -}; - -/** - * @group Operations - * @category Outputs - */ -export type PartiallySettleLegsOutput = { - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ -export const partiallySettleLegsOperationHandler: OperationHandler = - { - handle: async ( - operation: PartiallySettleLegsOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const builder = await partiallySettleLegsBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - scope.throwIfCanceled(); - - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( - convergence, - scope.confirmOptions - ); - - const output = await builder.sendAndConfirm(convergence, confirmOptions); - scope.throwIfCanceled(); - - return output; - }, - }; - -export type PartiallySettleLegsBuilderParams = PartiallySettleLegsInput; - -/** - * Partially settles legs - * - * ```ts - * const transactionBuilder = await convergence - * .rfqs() - * .builders() - * .partiallySettleLegs(); - * ``` - * - * @group Transaction Builders - * @category Constructors - */ -export const partiallySettleLegsBuilder = async ( - convergence: Convergence, - params: PartiallySettleLegsBuilderParams, - options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const rfqProgram = convergence.programs().getRfq(programs); - - const { rfq, response, maker, taker, legAmountToSettle } = params; - - const anchorRemainingAccounts: AccountMeta[] = []; - - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); - - const startIndex = parseInt(responseModel.settledLegs.toString()); - - for (let i = startIndex; i < startIndex + legAmountToSettle; i++) { - const leg = rfqModel.legs[i]; - const { legs } = await convergence.rfqs().getSettlementResult({ - rfq: rfqModel, - response: responseModel, - }); - const { receiver } = legs[i]; - - const instrumentProgramAccount: AccountMeta = { - pubkey: rfqModel.legs[i].getProgramId(), - isSigner: false, - isWritable: false, - }; - - const instrumentEscrowPda = new InstrumentPdasClient( - convergence - ).instrumentEscrow({ - response, - index: i, - rfqModel, - }); - - const baseAssetMint = await legToBaseAssetMint(convergence, leg); - - const legAccounts: AccountMeta[] = [ - //`escrow` - { - pubkey: instrumentEscrowPda, - isSigner: false, - isWritable: true, - }, - // `receiver_tokens` - { - pubkey: convergence - .tokens() - .pdas() - .associatedTokenAccount({ - mint: baseAssetMint!.address, - owner: receiver === 'maker' ? maker : taker, - programs, - }), - isSigner: false, - isWritable: true, - }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - ]; - - anchorRemainingAccounts.push(instrumentProgramAccount, ...legAccounts); - } - - return TransactionBuilder.make() - .setFeePayer(payer) - .add({ - instruction: ComputeBudgetProgram.setComputeUnitLimit({ - units: 1400000, - }), - signers: [], - }) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createPartiallySettleLegsInstruction( - { - protocol: convergence.protocol().pdas().protocol(), - rfq, - response, - anchorRemainingAccounts, - }, - { - legAmountToSettle, - }, - rfqProgram.address - ), - signers: [], - key: 'partiallySettleLegs', - }); -}; diff --git a/packages/js/src/plugins/rfqModule/operations/partiallySettleLegsAndSettle.ts b/packages/js/src/plugins/rfqModule/operations/partiallySettleLegsAndSettle.ts deleted file mode 100644 index f46770c71..000000000 --- a/packages/js/src/plugins/rfqModule/operations/partiallySettleLegsAndSettle.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; - -import { Convergence } from '../../../Convergence'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, - makeConfirmOptionsFinalizedOnMainnet, -} from '../../../types'; -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { settleBuilder } from './settle'; -import { partiallySettleLegsBuilder } from './partiallySettleLegs'; - -const Key = 'PartiallySettleLegsAndSettleOperation' as const; - -/** - * Partially settles legs and settles the remaining legs - * - * ```ts - * const quoteAsset = instrumentClient.createQuote(new SpotInstrument(...)); - * - * await convergence - * .rfqs() - * .partiallySettleLegsAndSettle({ - * rfq: rfq.address, - * response: rfqResponse.address, - * side: Side.Bid, - * legAmountToPrepare: 3, - * quoteAsset - * }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const partiallySettleLegsAndSettleOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type PartiallySettleLegsAndSettleOperation = Operation< - typeof Key, - PartiallySettleLegsAndSettleInput, - PartiallySettleLegsAndSettleOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type PartiallySettleLegsAndSettleInput = { - /** - * The protocol address. - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The Rfq address. */ - rfq: PublicKey; - - /** The Response address. */ - response: PublicKey; - - /** The Maker's public key address. */ - maker: PublicKey; - - /** The Taker's public key address. */ - taker: PublicKey; - - /* - * Args - */ - - /** The number of legs to settle. */ - legAmountToSettle: number; -}; - -/** - * @group Operations - * @category Outputs - */ -export type PartiallySettleLegsAndSettleOutput = { - /** The blockchain response from sending and confirming the transaction. */ - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ - -export const partiallySettleLegsAndSettleOperationHandler: OperationHandler = - { - handle: async ( - operation: PartiallySettleLegsAndSettleOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const { rfq } = operation.input; - - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( - convergence, - scope.confirmOptions - ); - - let settleRfqBuilder = await settleBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - scope.throwIfCanceled(); - - const rfqModel = await convergence - .rfqs() - .findRfqByAddress({ address: rfq }); - - let slicedIndex = rfqModel.legs.length; - - while (settleRfqBuilder.checkTransactionFits()) { - const index = Math.trunc(slicedIndex / 2); - // const startIndex = rfqModel.legs.length - index; - const startIndex = rfqModel.legs.length - index + 3; - - settleRfqBuilder = await settleBuilder( - convergence, - { - ...operation.input, - startIndex, - }, - scope - ); - - slicedIndex = index; - } - - if (slicedIndex < rfqModel.legs.length) { - let partiallySettleSlicedLegAmount = rfqModel.legs.length - slicedIndex; - - let partiallySettleBuilder = await partiallySettleLegsBuilder( - convergence, - { - ...operation.input, - legAmountToSettle: partiallySettleSlicedLegAmount, - }, - scope - ); - - while (partiallySettleBuilder.checkTransactionFits()) { - const halvedLegAmount = Math.trunc( - partiallySettleSlicedLegAmount / 2 - ); - - partiallySettleBuilder = await partiallySettleLegsBuilder( - convergence, - { - ...operation.input, - legAmountToSettle: halvedLegAmount, - }, - scope - ); - - partiallySettleSlicedLegAmount = halvedLegAmount; - } - - await partiallySettleBuilder.sendAndConfirm( - convergence, - confirmOptions - ); - scope.throwIfCanceled(); - - let x = partiallySettleSlicedLegAmount; - - if (partiallySettleSlicedLegAmount < rfqModel.legs.length) { - while (x + slicedIndex < rfqModel.legs.length) { - const nextPartiallySettleLegs = - rfqModel.legs.length - slicedIndex - x; - - const nextPartiallySettleBuilder = await partiallySettleLegsBuilder( - convergence, - { - ...operation.input, - legAmountToSettle: nextPartiallySettleLegs, - }, - scope - ); - - await nextPartiallySettleBuilder.sendAndConfirm( - convergence, - confirmOptions - ); - scope.throwIfCanceled(); - - x += nextPartiallySettleLegs; - } - } - } - - const output = await settleRfqBuilder.sendAndConfirm( - convergence, - confirmOptions - ); - scope.throwIfCanceled(); - - return { ...output }; - }, - }; diff --git a/packages/js/src/plugins/rfqModule/operations/partlyRevertSettlementPreparation.ts b/packages/js/src/plugins/rfqModule/operations/partlyRevertSettlementPreparation.ts index fd193db0b..e71a5ddc3 100644 --- a/packages/js/src/plugins/rfqModule/operations/partlyRevertSettlementPreparation.ts +++ b/packages/js/src/plugins/rfqModule/operations/partlyRevertSettlementPreparation.ts @@ -1,5 +1,5 @@ import { PublicKey, AccountMeta } from '@solana/web3.js'; -import { createPartlyRevertSettlementPreparationInstruction } from '@convergence-rfq/rfq'; +import { createPartlyRevertEscrowSettlementPreparationInstruction } from '@convergence-rfq/rfq'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; @@ -156,6 +156,13 @@ export const partlyRevertSettlementPreparationBuilder = async ( .rfqs() .findResponseByAddress({ address: response }); + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } + const sidePreparedLegs: number = side === 'taker' ? parseInt(responseModel.takerPreparedLegs.toString()) @@ -211,7 +218,7 @@ export const partlyRevertSettlementPreparationBuilder = async ( .setFeePayer(payer) .addTxPriorityFeeIx(convergence) .add({ - instruction: createPartlyRevertSettlementPreparationInstruction( + instruction: createPartlyRevertEscrowSettlementPreparationInstruction( { protocol: convergence.protocol().pdas().protocol(), rfq, diff --git a/packages/js/src/plugins/rfqModule/operations/prepareMoreLegsSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareMoreLegsSettlement.ts index bb2e0eaa7..293b524bd 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareMoreLegsSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareMoreLegsSettlement.ts @@ -5,7 +5,7 @@ import { ComputeBudgetProgram, } from '@solana/web3.js'; import { - createPrepareMoreLegsSettlementInstruction, + createPrepareMoreEscrowLegsSettlementInstruction, AuthoritySide, } from '@convergence-rfq/rfq'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; @@ -176,6 +176,13 @@ export const prepareMoreLegsSettlementBuilder = async ( .rfqs() .findResponseByAddress({ address: response }); + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } + const side = caller.publicKey.toBase58() == responseModel.maker.toBase58() ? AuthoritySide.Maker @@ -257,7 +264,7 @@ export const prepareMoreLegsSettlementBuilder = async ( }) .addTxPriorityFeeIx(convergence) .add({ - instruction: createPrepareMoreLegsSettlementInstruction( + instruction: createPrepareMoreEscrowLegsSettlementInstruction( { caller: caller.publicKey, protocol: convergence.protocol().pdas().protocol(), diff --git a/packages/js/src/plugins/rfqModule/operations/preparePrintTradeSettlement.ts b/packages/js/src/plugins/rfqModule/operations/preparePrintTradeSettlement.ts new file mode 100644 index 000000000..8f73412f5 --- /dev/null +++ b/packages/js/src/plugins/rfqModule/operations/preparePrintTradeSettlement.ts @@ -0,0 +1,193 @@ +import { createPreparePrintTradeSettlementInstruction } from '@convergence-rfq/rfq'; +import { PublicKey } from '@solana/web3.js'; + +import { SendAndConfirmTransactionResponse } from '../../rpcModule'; +import { Convergence } from '../../../Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + useOperation, + makeConfirmOptionsFinalizedOnMainnet, +} from '../../../types'; +import { + TransactionBuilder, + TransactionBuilderOptions, +} from '../../../utils/TransactionBuilder'; +import { getAuthoritySide } from '../helpers'; +import { toSolitaAuthoritySide } from '../models'; +import { prependWithProviderProgram } from '@/plugins/printTradeModule'; + +const Key = 'PreparePrintTradeSettlementOperation' as const; + +/** + * @group Operations + * @category Constructors + */ +export const preparePrintTradeSettlementOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type PreparePrintTradeSettlementOperation = Operation< + typeof Key, + PreparePrintTradeSettlementInput, + PreparePrintTradeSettlementOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type PreparePrintTradeSettlementInput = { + /** The address of the Rfq account. */ + rfq: PublicKey; + + /** The address of the Response account. */ + response: PublicKey; +}; + +/** + * @group Operations + * @category Outputs + */ +export type PreparePrintTradeSettlementOutput = { + /** The blockchain response from sending and confirming the transaction. */ + response: SendAndConfirmTransactionResponse; +}; + +/** + * @group Operations + * @category Handlers + */ +export const preparePrintTradeSettlementOperationHandler: OperationHandler = + { + handle: async ( + operation: PreparePrintTradeSettlementOperation, + convergence: Convergence, + scope: OperationScope + ): Promise => { + const builders = await preparePrintTradeSettlementBuilders( + convergence, + { + ...operation.input, + }, + scope + ); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + convergence, + scope.confirmOptions + ); + + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const txs = builders.map((x) => x.toTransaction(lastValidBlockHeight)); + + const signedTxs = await convergence.identity().signAllTransactions(txs); + + const outputs = []; + for (const signedTx of signedTxs) { + const output = await convergence + .rpc() + .serializeAndSendTransaction( + signedTx, + lastValidBlockHeight, + confirmOptions + ); + + outputs.push(output); + } + + scope.throwIfCanceled(); + + return { response: outputs[outputs.length - 1] }; + }, + }; + +/** + * @group Transaction Builders + * @category Inputs + */ +export type PreparePrintTradeSettlementBuilderParams = + PreparePrintTradeSettlementInput; + +/** + * Prepares for settlement + * + * ```ts + * const transactionBuilder = convergence + * .rfqs() + * .builders() + * .preparePrintTradeSettlement({ address }); + * ``` + * + * @group Transaction Builders + * @category Constructors + */ +export const preparePrintTradeSettlementBuilders = async ( + cvg: Convergence, + params: PreparePrintTradeSettlementBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const { rfq, response } = params; + + const caller = cvg.identity(); + const rfqProgram = cvg.programs().getRfq(programs); + + const rfqModel = await cvg.rfqs().findRfqByAddress({ address: rfq }); + const responseModel = await cvg + .rfqs() + .findResponseByAddress({ address: response }); + + if ( + responseModel.model !== 'printTradeResponse' || + rfqModel.model !== 'printTradeRfq' + ) { + throw new Error('Response is not settled as a print trade!'); + } + + const side = getAuthoritySide(caller.publicKey, rfqModel, responseModel); + if (side === null) { + throw Error('Passed caller is neither a taker nor a maker'); + } + + const { printTrade } = rfqModel; + + const { accounts: printTradeAccounts, builders } = + await printTrade.getSettlementPreparations( + rfqModel, + responseModel, + side, + options + ); + const remainingAccounts = prependWithProviderProgram( + printTrade, + printTradeAccounts + ); + + const preparePrintTradeIx = { + instruction: createPreparePrintTradeSettlementInstruction( + { + caller: caller.publicKey, + protocol: cvg.protocol().pdas().protocol(), + rfq, + response, + anchorRemainingAccounts: remainingAccounts, + }, + { + side: toSolitaAuthoritySide(side), + }, + rfqProgram.address + ), + signers: [caller], + key: 'preparePrintTradeSettlement', + }; + + return TransactionBuilder.make() + .setFeePayer(payer) + .add(...builders, preparePrintTradeIx) + .divideToMultipleBuildersThatFit(); +}; diff --git a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts index 91c0bbe88..9e655fe04 100644 --- a/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts +++ b/packages/js/src/plugins/rfqModule/operations/prepareSettlement.ts @@ -1,5 +1,5 @@ import { - createPrepareSettlementInstruction, + createPrepareEscrowSettlementInstruction, AuthoritySide, } from '@convergence-rfq/rfq'; import { @@ -25,7 +25,7 @@ import { TransactionBuilder, TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; -import { Rfq } from '../../rfqModule'; +import { EscrowRfq, Rfq } from '../../rfqModule'; import { getOrCreateATAtxBuilder } from '../../../utils/ata'; import { Mint } from '../../tokenModule'; import { InstrumentPdasClient } from '../../instrumentModule'; @@ -147,6 +147,10 @@ export const prepareSettlementOperationHandler: OperationHandler { +const doesRfqLegContainsPsyoptionsAmerican = (rfq: EscrowRfq) => { return rfq.legs.some((leg) => leg.getProgramId().equals(psyoptionsAmericanInstrumentProgram.address) ); }; -const doesRfqLegContainsPsyoptionsEuropean = (rfq: Rfq) => { +const doesRfqLegContainsPsyoptionsEuropean = (rfq: EscrowRfq) => { return rfq.legs.some((leg) => leg.getProgramId().equals(psyoptionsEuropeanInstrumentProgram.address) ); diff --git a/packages/js/src/plugins/rfqModule/operations/respondToRfq.ts b/packages/js/src/plugins/rfqModule/operations/respondToRfq.ts index 9ea6fa715..4761f477d 100644 --- a/packages/js/src/plugins/rfqModule/operations/respondToRfq.ts +++ b/packages/js/src/plugins/rfqModule/operations/respondToRfq.ts @@ -1,5 +1,5 @@ import { createRespondToRfqInstruction } from '@convergence-rfq/rfq'; -import { PublicKey, AccountMeta, ComputeBudgetProgram } from '@solana/web3.js'; +import { PublicKey, ComputeBudgetProgram, AccountMeta } from '@solana/web3.js'; import BN from 'bn.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; @@ -10,7 +10,6 @@ import { OperationHandler, OperationScope, useOperation, - Signer, } from '../../../types'; import { TransactionBuilder, @@ -19,7 +18,12 @@ import { import { Quote, Rfq } from '../models'; import { toSolitaQuote } from '../models/Quote'; import { rfqProgram } from '../program'; +import { getRiskEngineAccounts } from '@/plugins/riskEngineModule/helpers'; import { convertTimestampToSeconds } from '@/utils'; +import { + AdditionalResponseData, + prependWithProviderProgram, +} from '@/plugins/printTradeModule'; const getNextResponsePdaAndDistinguisher = async ( cvg: Convergence, @@ -113,39 +117,9 @@ export type RespondToRfqInput = { rfq: PublicKey; /** - * The maker of the Response as a Signer. - * - * @defaultValue `convergence.identity()` - */ - maker?: Signer; - - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** - * Optional address of the taker collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: response.maker })` - */ - collateralInfo?: PublicKey; - - /** - * Optional address of the maker collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas().collateralTokens({ user: maker.publicKey })` - */ - collateralToken?: PublicKey; - - /** - * Optional address of the risk engine account. - * - * @defaultValue `convergence.programs().getRiskEngine(programs)` + * Is sometimes required to pass for print trades */ - riskEngine?: PublicKey; + additionalData?: AdditionalResponseData; }; /** @@ -236,19 +210,20 @@ export const respondToRfqBuilder = async ( rfq, bid = null, ask = null, - maker = convergence.identity(), - protocol = convergence.protocol().pdas().protocol(), - riskEngine = convergence.programs().getRiskEngine(programs).address, - collateralInfo = convergence.collateral().pdas().collateralInfo({ - user: maker.publicKey, - programs, - }), - collateralToken = convergence.collateral().pdas().collateralToken({ - user: maker.publicKey, - programs, - }), expirationTimestamp, + additionalData, } = params; + const maker = convergence.identity(); + const protocol = convergence.protocol().pdas().protocol(); + const riskEngine = convergence.programs().getRiskEngine(programs).address; + const collateralInfo = convergence.collateral().pdas().collateralInfo({ + user: maker.publicKey, + programs, + }); + const collateralToken = convergence.collateral().pdas().collateralToken({ + user: maker.publicKey, + programs, + }); if (!bid && !ask) { throw new Error('Must provide either a bid and/or ask'); @@ -256,6 +231,19 @@ export const respondToRfqBuilder = async ( const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); + let validateResponseAccounts: AccountMeta[] = []; + if (rfqModel.model === 'escrowRfq' && additionalData !== undefined) { + throw new Error( + 'Escrow rfqs does not allow passing additional response data' + ); + } + if (rfqModel.model === 'printTradeRfq') { + validateResponseAccounts = prependWithProviderProgram( + rfqModel.printTrade, + await rfqModel.printTrade.getValidateResponseAccounts(additionalData) + ); + } + const rfqExpirationTimestampSeconds = convertTimestampToSeconds(rfqModel.creationTimestamp) + rfqModel.activeWindow; @@ -287,35 +275,10 @@ export const respondToRfqBuilder = async ( rfqModel ); - // TODO: DRY - const baseAssetIndexValuesSet: Set = new Set(); - for (const leg of rfqModel.legs) { - baseAssetIndexValuesSet.add(leg.getBaseAssetIndex().value); - } - const baseAssetAccounts: AccountMeta[] = []; - const baseAssetIndexValues = Array.from(baseAssetIndexValuesSet); - const oracleAccounts: AccountMeta[] = []; - for (const index of baseAssetIndexValues) { - const baseAsset = convergence.protocol().pdas().baseAsset({ index }); - const baseAssetAccount: AccountMeta = { - pubkey: baseAsset, - isSigner: false, - isWritable: false, - }; - - baseAssetAccounts.push(baseAssetAccount); - - const baseAssetModel = await convergence - .protocol() - .findBaseAssetByAddress({ address: baseAsset }); - if (baseAssetModel.priceOracle.address) { - oracleAccounts.push({ - pubkey: baseAssetModel.priceOracle.address, - isSigner: false, - isWritable: false, - }); - } - } + const riskEngineAccounts = await getRiskEngineAccounts( + convergence, + rfqModel.legs + ); const defaultPubkey = PublicKey.default; const whitelist = @@ -360,13 +323,8 @@ export const respondToRfqBuilder = async ( whitelist, maker: maker.publicKey, anchorRemainingAccounts: [ - { - pubkey: convergence.riskEngine().pdas().config(), - isSigner: false, - isWritable: false, - }, - ...baseAssetAccounts, - ...oracleAccounts, + ...validateResponseAccounts, + ...riskEngineAccounts, ], }, { @@ -374,6 +332,7 @@ export const respondToRfqBuilder = async ( ask: ask && toSolitaQuote(ask, rfqModel.quoteAsset.getDecimals()), pdaDistinguisher, expirationTimestamp: expirationTimestampBn, + additionalData: additionalData?.serialize() ?? Buffer.from([]), } ), signers: [maker], diff --git a/packages/js/src/plugins/rfqModule/operations/revertSettlementPreparation.ts b/packages/js/src/plugins/rfqModule/operations/revertSettlementPreparation.ts index ea8b19801..1982a2769 100644 --- a/packages/js/src/plugins/rfqModule/operations/revertSettlementPreparation.ts +++ b/packages/js/src/plugins/rfqModule/operations/revertSettlementPreparation.ts @@ -1,5 +1,8 @@ import { PublicKey, AccountMeta } from '@solana/web3.js'; -import { createRevertSettlementPreparationInstruction } from '@convergence-rfq/rfq'; +import { + createRevertEscrowSettlementPreparationInstruction, + createRevertPrintTradeSettlementPreparationPreparationInstruction, +} from '@convergence-rfq/rfq'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; @@ -17,7 +20,14 @@ import { } from '../../../utils/TransactionBuilder'; import { InstrumentPdasClient } from '../../instrumentModule'; import { AuthoritySide, toSolitaAuthoritySide } from '../models/AuthoritySide'; +import { + EscrowResponse, + EscrowRfq, + PrintTradeResponse, + PrintTradeRfq, +} from '../models'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; +import { prependWithProviderProgram } from '@/plugins/printTradeModule'; const Key = 'RevertSettlementPreparationOperation' as const; @@ -51,23 +61,9 @@ export type RevertSettlementPreparationOperation = Operation< * @category Inputs */ export type RevertSettlementPreparationInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The Rfq address. */ - rfq: PublicKey; - /** The Response address. */ response: PublicKey; - /* - * Args - */ - /** * The side (Maker or Taker) that is reverting * settlement preparation. @@ -137,19 +133,75 @@ export const revertSettlementPreparationBuilder = async ( params: RevertSettlementPreparationBuilderParams, options: TransactionBuilderOptions = {} ): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const rfqProgram = convergence.programs().getRfq(programs); + const responseModel = await convergence + .rfqs() + .findResponseByAddress({ address: params.response }); + const rfqModel = await convergence + .rfqs() + .findRfqByAddress({ address: responseModel.rfq }); + + if ( + responseModel.model === 'escrowResponse' && + rfqModel.model === 'escrowRfq' + ) { + return revertEscrowSettlementPreparationBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + side: params.side, + }, + options + ); + } else if ( + responseModel.model === 'printTradeResponse' && + rfqModel.model === 'printTradeRfq' + ) { + return revertPrintTradeSettlementPreparationBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + side: params.side, + }, + options + ); + } - const { rfq, response, side } = params; + throw new Error('Rfq type does not match with response type!'); +}; - const anchorRemainingAccounts: AccountMeta[] = []; +export type RevertEscrowSettlementPreparationBuilderParams = { + response: PublicKey | EscrowResponse; + rfq?: EscrowRfq; + side: AuthoritySide; +}; - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); +export const revertEscrowSettlementPreparationBuilder = async ( + cvg: Convergence, + params: RevertEscrowSettlementPreparationBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const { response, rfq, side } = params; + + const responseModel = + response instanceof PublicKey + ? await cvg.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? (await cvg.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } - const spotInstrumentProgram = convergence.programs().getSpotInstrument(); + const rfqProgram = cvg.programs().getRfq(programs); + const anchorRemainingAccounts: AccountMeta[] = []; + const spotInstrumentProgram = cvg.programs().getSpotInstrument(); const sidePreparedLegs: number = side === 'taker' @@ -157,10 +209,8 @@ export const revertSettlementPreparationBuilder = async ( : parseInt(responseModel.makerPreparedLegs.toString()); for (let i = 0; i < sidePreparedLegs; i++) { - const instrumentEscrowPda = new InstrumentPdasClient( - convergence - ).instrumentEscrow({ - response, + const instrumentEscrowPda = new InstrumentPdasClient(cvg).instrumentEscrow({ + response: responseModel.address, index: i, rfqModel, }); @@ -173,7 +223,7 @@ export const revertSettlementPreparationBuilder = async ( const leg = rfqModel.legs[i]; - const baseAssetMint = await legToBaseAssetMint(convergence, leg); + const baseAssetMint = await legToBaseAssetMint(cvg, leg); const legAccounts: AccountMeta[] = [ //`escrow` @@ -184,7 +234,7 @@ export const revertSettlementPreparationBuilder = async ( }, // `receiver_tokens` { - pubkey: convergence + pubkey: cvg .tokens() .pdas() .associatedTokenAccount({ @@ -207,8 +257,8 @@ export const revertSettlementPreparationBuilder = async ( isWritable: false, }; - const quoteEscrowPda = new InstrumentPdasClient(convergence).quoteEscrow({ - response, + const quoteEscrowPda = new InstrumentPdasClient(cvg).quoteEscrow({ + response: responseModel.address, program: spotInstrumentProgram.address, }); @@ -221,7 +271,7 @@ export const revertSettlementPreparationBuilder = async ( }, // `receiver_tokens` { - pubkey: convergence + pubkey: cvg .tokens() .pdas() .associatedTokenAccount({ @@ -239,13 +289,13 @@ export const revertSettlementPreparationBuilder = async ( return TransactionBuilder.make() .setFeePayer(payer) - .addTxPriorityFeeIx(convergence) + .addTxPriorityFeeIx(cvg) .add({ - instruction: createRevertSettlementPreparationInstruction( + instruction: createRevertEscrowSettlementPreparationInstruction( { - protocol: convergence.protocol().pdas().protocol(), - rfq, - response, + protocol: cvg.protocol().pdas().protocol(), + rfq: rfqModel.address, + response: responseModel.address, anchorRemainingAccounts, }, { @@ -257,3 +307,70 @@ export const revertSettlementPreparationBuilder = async ( key: 'revertSettlementPreparation', }); }; + +export type RevertPrintTradeSettlementPreparationBuilderParams = { + response: PublicKey | PrintTradeResponse; + rfq?: PrintTradeRfq; + side: AuthoritySide; +}; + +export const revertPrintTradeSettlementPreparationBuilder = async ( + cvg: Convergence, + params: RevertPrintTradeSettlementPreparationBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const { response, rfq, side } = params; + + const responseModel = + response instanceof PublicKey + ? await cvg.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? (await cvg.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'printTradeResponse' || + rfqModel.model !== 'printTradeRfq' + ) { + throw new Error('Response is not settled as a print trade!'); + } + + const { accounts: remainingAccounts, postBuilders } = + await rfqModel.printTrade.getRevertPreparations( + rfqModel, + responseModel, + side, + options + ); + + const fullRemainingAccounts = prependWithProviderProgram( + rfqModel.printTrade, + remainingAccounts + ); + + const rfqProgram = cvg.programs().getRfq(programs); + + return TransactionBuilder.make() + .setFeePayer(payer) + .add( + { + instruction: + createRevertPrintTradeSettlementPreparationPreparationInstruction( + { + protocol: cvg.protocol().pdas().protocol(), + rfq: rfqModel.address, + response: responseModel.address, + anchorRemainingAccounts: fullRemainingAccounts, + }, + { + side: toSolitaAuthoritySide(side), + }, + rfqProgram.address + ), + signers: [], + key: 'revertSettlementPreparation', + }, + ...postBuilders + ); +}; diff --git a/packages/js/src/plugins/rfqModule/operations/settle.ts b/packages/js/src/plugins/rfqModule/operations/settle.ts index fc09569e7..295a724b2 100644 --- a/packages/js/src/plugins/rfqModule/operations/settle.ts +++ b/packages/js/src/plugins/rfqModule/operations/settle.ts @@ -1,4 +1,7 @@ -import { createSettleInstruction } from '@convergence-rfq/rfq'; +import { + createSettleEscrowInstruction, + createSettlePrintTradeInstruction, +} from '@convergence-rfq/rfq'; import { PublicKey, AccountMeta, ComputeBudgetProgram } from '@solana/web3.js'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; @@ -10,13 +13,25 @@ import { OperationScope, useOperation, makeConfirmOptionsFinalizedOnMainnet, + Program, } from '../../../types'; import { TransactionBuilder, TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; import { InstrumentPdasClient } from '../../instrumentModule'; +import { + EscrowResponse, + EscrowRfq, + PrintTradeResponse, + PrintTradeRfq, +} from '../models'; +import { Receiver } from './getSettlementResult'; import { legToBaseAssetMint } from '@/plugins/instrumentModule'; +import { prependWithProviderProgram } from '@/plugins/printTradeModule'; +import { spotInstrumentProgram } from '@/plugins/spotInstrumentModule'; +import { InstructionUniquenessTracker, getOrCreateATAtxBuilder } from '@/utils'; +import { Protocol } from '@/plugins/protocolModule'; const Key = 'SettleOperation' as const; @@ -45,32 +60,8 @@ export type SettleOperation = Operation; * @category Inputs */ export type SettleInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The address of the RFQ account. */ - rfq: PublicKey; - /** The address of the response account. */ response: PublicKey; - - /** The maker public key address. */ - maker: PublicKey; - - /** The taker public key address. */ - taker: PublicKey; - - /** - * Optional start index to corresponding to the first leg to settle. Used internally by - * Convergence SDK and does not need to be passed manually. - * - * @defaultValue `0` - * */ - startIndex?: number; }; /** @@ -92,7 +83,7 @@ export const settleOperationHandler: OperationHandler = { convergence: Convergence, scope: OperationScope ): Promise => { - const builder = await settleBuilder( + const { ataTxBuilderArray, settleTxBuilder } = await settleBuilder( convergence, { ...operation.input, @@ -106,10 +97,30 @@ export const settleOperationHandler: OperationHandler = { scope.confirmOptions ); - const output = await builder.sendAndConfirm(convergence, confirmOptions); + const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); + const dedupAtaBuiders = + InstructionUniquenessTracker.dedup(ataTxBuilderArray); + const txs = [...dedupAtaBuiders, settleTxBuilder].map((txBuilder) => + txBuilder.toTransaction(lastValidBlockHeight) + ); + const signedTxs = await convergence.identity().signAllTransactions(txs); + + const outputs = []; + for (const signedTx of signedTxs) { + const output = await convergence + .rpc() + .serializeAndSendTransaction( + signedTx, + lastValidBlockHeight, + confirmOptions + ); + + outputs.push(output); + } + scope.throwIfCanceled(); - return { ...output }; + return { response: outputs[outputs.length - 1] }; }, }; @@ -119,16 +130,12 @@ export const settleOperationHandler: OperationHandler = { */ export type SettleBuilderParams = SettleInput; +export type SettleBuilderResult = { + ataTxBuilderArray: TransactionBuilder[]; + settleTxBuilder: TransactionBuilder; +}; + /** - * Settles - * - * ```ts - * const transactionBuilder = convergence - * .rfqs() - * .builders() - * .settle({ address }); - * ``` - * * @group Transaction Builders * @category Constructors */ @@ -136,100 +143,281 @@ export const settleBuilder = async ( convergence: Convergence, params: SettleBuilderParams, options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { rfq, response, maker, taker } = params; - - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); +): Promise => { const responseModel = await convergence .rfqs() - .findResponseByAddress({ address: response }); + .findResponseByAddress({ address: params.response }); + const rfqModel = await convergence + .rfqs() + .findRfqByAddress({ address: responseModel.rfq }); + + if ( + responseModel.model === 'escrowResponse' && + rfqModel.model === 'escrowRfq' + ) { + return settleEscrowBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + }, + options + ); + } else if ( + responseModel.model === 'printTradeResponse' && + rfqModel.model === 'printTradeRfq' + ) { + return settlePrintTradeBuilder( + convergence, + { + response: responseModel, + rfq: rfqModel, + }, + options + ); + } - const { startIndex = parseInt(responseModel.settledLegs.toString()) } = - params; + throw new Error('Rfq type does not match with response type!'); +}; - const rfqProgram = convergence.programs().getRfq(programs); +export type SettleEscrowBuilderParams = { + response: PublicKey | EscrowResponse; + rfq?: EscrowRfq; + startIndex?: number; +}; +export const settleEscrowBuilder = async ( + cvg: Convergence, + params: SettleEscrowBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + const { response, rfq, startIndex = 0 } = params; + + const responseModel = + response instanceof PublicKey + ? await cvg.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? (await cvg.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'escrowResponse' || + rfqModel.model !== 'escrowRfq' + ) { + throw new Error('Response is not settled as an escrow!'); + } + + const rfqProgram = cvg.programs().getRfq(programs); + const protocol = await cvg.protocol().get(); + + const ataTxBuilderArray: TransactionBuilder[] = []; const anchorRemainingAccounts: AccountMeta[] = []; - const spotInstrumentProgram = convergence.programs().getSpotInstrument(); - const { legs, quote } = await convergence.rfqs().getSettlementResult({ + const { legs, quote } = await cvg.rfqs().getSettlementResult({ response: responseModel, rfq: rfqModel, }); + const accountsToAddContext = { + cvg, + protocol, + rfq: rfqModel, + response: responseModel, + programs, + }; + for (let legIndex = startIndex; legIndex < rfqModel.legs.length; legIndex++) { const leg = rfqModel.legs[legIndex]; const { receiver } = legs[legIndex]; - const baseAssetMint = await legToBaseAssetMint(convergence, leg); - - const instrumentProgramAccount: AccountMeta = { - pubkey: rfqModel.legs[legIndex].getProgramId(), - isSigner: false, - isWritable: false, - }; - - const instrumentEscrowPda = new InstrumentPdasClient( - convergence - ).instrumentEscrow({ - response, - index: legIndex, - rfqModel, - }); + const baseAssetMint = await legToBaseAssetMint(cvg, leg); - const legAccounts: AccountMeta[] = [ - //`escrow` - { - pubkey: instrumentEscrowPda, - isSigner: false, - isWritable: true, - }, - // `receiver_tokens` - { - pubkey: convergence - .tokens() - .pdas() - .associatedTokenAccount({ - mint: baseAssetMint!.address, - owner: receiver === 'maker' ? maker : taker, - programs, - }), - isSigner: false, - isWritable: true, - }, - { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, - ]; + if (leg.getProgramId().equals(spotInstrumentProgram.address)) { + const { ataTxBuilder, accounts } = await getSettleAccountsSpot( + baseAssetMint.address, + receiver, + { + leg: legIndex, + }, + accountsToAddContext + ); + + if (ataTxBuilder !== undefined) { + ataTxBuilderArray.push(ataTxBuilder); + } + + anchorRemainingAccounts.push(...accounts); + } else { + const accounts = getSettleAccountsNonSpot( + leg.getProgramId(), + baseAssetMint.address, + receiver, + { leg: legIndex }, + accountsToAddContext + ); + + anchorRemainingAccounts.push(...accounts); + } + } - anchorRemainingAccounts.push(instrumentProgramAccount, ...legAccounts); + const { accounts, ataTxBuilder } = await getSettleAccountsSpot( + rfqModel.quoteMint, + quote.receiver, + 'quote', + accountsToAddContext + ); + if (ataTxBuilder !== undefined) { + ataTxBuilderArray.push(ataTxBuilder); } + anchorRemainingAccounts.push(...accounts); - const spotInstrumentProgramAccount: AccountMeta = { - pubkey: spotInstrumentProgram.address, - isSigner: false, - isWritable: false, + const settleTxBuilder = TransactionBuilder.make() + .setFeePayer(payer) + .add({ + instruction: ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_400_000, + }), + signers: [], + }) + .addTxPriorityFeeIx(cvg) + .add({ + instruction: createSettleEscrowInstruction( + { + protocol: cvg.protocol().pdas().protocol(), + rfq: rfqModel.address, + response: responseModel.address, + anchorRemainingAccounts, + }, + rfqProgram.address + ), + signers: [], + key: 'settle', + }); + + return { + ataTxBuilderArray, + settleTxBuilder, }; +}; - const quoteEscrowPda = new InstrumentPdasClient(convergence).quoteEscrow({ - response, - program: spotInstrumentProgram.address, - }); +export const getSettleAccountsSpot = async ( + mint: PublicKey, + receiver: Receiver, + asset: { leg: number } | 'quote', + context: { + cvg: Convergence; + protocol: Protocol; + rfq: EscrowRfq; + response: EscrowResponse; + programs: Program[] | undefined; + } +): Promise<{ + ataTxBuilder?: TransactionBuilder; + accounts: AccountMeta[]; +}> => { + const { cvg, rfq, response, protocol, programs } = context; + const programId = spotInstrumentProgram.address; + const pdaClient = new InstrumentPdasClient(cvg); + const escrow = + asset === 'quote' + ? pdaClient.quoteEscrow({ + response: response.address, + program: programId, + }) + : pdaClient.instrumentEscrow({ + response: response.address, + index: asset.leg, + rfqModel: rfq, + }); + + const { ataPubKey: authorityAtaKey, txBuilder: ataTxBuilder } = + await getOrCreateATAtxBuilder(cvg, mint, protocol.authority, programs); + + const accounts = [ + { + pubkey: programId, + isSigner: false, + isWritable: false, + }, + { + pubkey: cvg.spotInstrument().pdas().config(), + isSigner: false, + isWritable: false, + }, + { + pubkey: escrow, + isSigner: false, + isWritable: true, + }, + { + pubkey: cvg + .tokens() + .pdas() + .associatedTokenAccount({ + mint, + owner: receiver === 'maker' ? response.maker : rfq.taker, + programs, + }), + isSigner: false, + isWritable: true, + }, + { + pubkey: authorityAtaKey, + isSigner: false, + isWritable: true, + }, + { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, + ]; - const quoteAccounts: AccountMeta[] = [ - //`escrow` + return { ataTxBuilder, accounts }; +}; + +export const getSettleAccountsNonSpot = ( + programId: PublicKey, + mint: PublicKey, + receiver: Receiver, + asset: { leg: number } | 'quote', + context: { + cvg: Convergence; + protocol: Protocol; + rfq: EscrowRfq; + response: EscrowResponse; + programs: Program[] | undefined; + } +) => { + const { cvg, rfq, response, programs } = context; + const pdaClient = new InstrumentPdasClient(cvg); + const escrow = + asset === 'quote' + ? pdaClient.quoteEscrow({ + response: response.address, + program: programId, + }) + : pdaClient.instrumentEscrow({ + response: response.address, + index: asset.leg, + rfqModel: rfq, + }); + + return [ + { + pubkey: programId, + isSigner: false, + isWritable: false, + }, { - pubkey: quoteEscrowPda, + pubkey: escrow, isSigner: false, isWritable: true, }, - // `receiver_tokens` { - pubkey: convergence + pubkey: cvg .tokens() .pdas() .associatedTokenAccount({ - mint: rfqModel.quoteMint, - owner: quote.receiver === 'maker' ? maker : taker, + mint, + owner: receiver === 'maker' ? response.maker : rfq.taker, programs, }), isSigner: false, @@ -237,29 +425,69 @@ export const settleBuilder = async ( }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, ]; +}; + +export type SettlePrintTradeBuilderParams = { + response: PublicKey | PrintTradeResponse; + rfq?: PrintTradeRfq; +}; + +export const settlePrintTradeBuilder = async ( + convergence: Convergence, + params: SettlePrintTradeBuilderParams, + options: TransactionBuilderOptions = {} +): Promise => { + const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; + const { response, rfq } = params; + + const responseModel = + response instanceof PublicKey + ? await convergence.rfqs().findResponseByAddress({ address: response }) + : response; + const rfqModel = + rfq ?? + (await convergence.rfqs().findRfqByAddress({ address: responseModel.rfq })); + + if ( + responseModel.model !== 'printTradeResponse' || + rfqModel.model !== 'printTradeRfq' + ) { + throw new Error('Response is not settled as a print trade!'); + } - anchorRemainingAccounts.push(spotInstrumentProgramAccount, ...quoteAccounts); + const rfqProgram = convergence.programs().getRfq(programs); - return TransactionBuilder.make() + const remainingAccounts = prependWithProviderProgram( + rfqModel.printTrade, + await rfqModel.printTrade.getSettlementAccounts(rfqModel, responseModel) + ); + + const settleTxBuilder = TransactionBuilder.make() .setFeePayer(payer) - .add({ - instruction: ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_400_000, - }), - signers: [], - }) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createSettleInstruction( - { - protocol: convergence.protocol().pdas().protocol(), - rfq, - response, - anchorRemainingAccounts, - }, - rfqProgram.address - ), - signers: [], - key: 'settle', - }); + .add( + { + instruction: ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_400_000, + }), + signers: [], + }, + { + instruction: createSettlePrintTradeInstruction( + { + protocol: convergence.protocol().pdas().protocol(), + rfq: rfqModel.address, + response: responseModel.address, + anchorRemainingAccounts: remainingAccounts, + }, + rfqProgram.address + ), + signers: [], + key: 'settle', + } + ); + + return { + ataTxBuilderArray: [], + settleTxBuilder, + }; }; diff --git a/packages/js/src/plugins/rfqModule/operations/settleOnePartyDefault.ts b/packages/js/src/plugins/rfqModule/operations/settleOnePartyDefault.ts deleted file mode 100644 index 3b69b4c9c..000000000 --- a/packages/js/src/plugins/rfqModule/operations/settleOnePartyDefault.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { createSettleOnePartyDefaultInstruction } from '@convergence-rfq/rfq'; -import { PublicKey } from '@solana/web3.js'; - -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { Convergence } from '../../../Convergence'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, - makeConfirmOptionsFinalizedOnMainnet, -} from '../../../types'; -import { - TransactionBuilder, - TransactionBuilderOptions, -} from '../../../utils/TransactionBuilder'; -import { protocolCache } from '../../protocolModule/cache'; - -const Key = 'SettleOnePartyDefaultOperation' as const; - -/** - * Settles one party default. - * - * ```ts - * await convergence - * .rfqs() - * .settleOnePartyDefault({ - * rfq: rfq.address, - * response: rfqResponse.address - * }; - * ``` - * - * @group Operations - * @category Constructors - */ -export const settleOnePartyDefaultOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type SettleOnePartyDefaultOperation = Operation< - typeof Key, - SettleOnePartyDefaultInput, - SettleOnePartyDefaultOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type SettleOnePartyDefaultInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol(),` - */ - protocol?: PublicKey; - - /** The address of the Rfq account. */ - rfq: PublicKey; - - /** The address of the Response account. */ - response: PublicKey; - - /** - * Optional address of the Taker's collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: rfq.taker })` - * - */ - takerCollateralInfo?: PublicKey; - - /** - * Optional address of the Maker's collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: response.maker })` - * - */ - makerCollateralInfo?: PublicKey; - - /** Optional address of the Taker's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: rfq.taker, - * })` - */ - takerCollateralTokens?: PublicKey; - - /** Optional address of the Maker's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: response.maker, - * })` - */ - makerCollateralTokens?: PublicKey; - - /** Optional address of the DAO's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: dao - * })` - */ - protocolCollateralTokens?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type SettleOnePartyDefaultOutput = { - /** The blockchain response from sending and confirming the transaction. */ - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ -export const settleOnePartyDefaultOperationHandler: OperationHandler = - { - handle: async ( - operation: SettleOnePartyDefaultOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const builder = await settleOnePartyDefaultBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - scope.throwIfCanceled(); - - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( - convergence, - scope.confirmOptions - ); - - const output = await builder.sendAndConfirm(convergence, confirmOptions); - scope.throwIfCanceled(); - - return { ...output }; - }, - }; - -/** - * @group Transaction Builders - * @category Inputs - */ -export type SettleOnePartyDefaultBuilderParams = SettleOnePartyDefaultInput; - -/** - * Settles one party default - * - * ```ts - * const transactionBuilder = convergence - * .rfqs() - * .builders() - * .settleOnePartyDefault({ address }); - * ``` - * - * @group Transaction Builders - * @category Constructors - */ -export const settleOnePartyDefaultBuilder = async ( - convergence: Convergence, - params: SettleOnePartyDefaultBuilderParams, - options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { rfq, response } = params; - - const protocol = await protocolCache.get(convergence); - - const rfqProgram = convergence.programs().getRfq(programs); - const tokenProgram = convergence.programs().getToken(programs); - - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); - - let { - takerCollateralInfo, - makerCollateralInfo, - takerCollateralTokens, - makerCollateralTokens, - protocolCollateralTokens, - } = params; - - const takerCollateralInfoPda = convergence - .collateral() - .pdas() - .collateralInfo({ - user: rfqModel.taker, - programs, - }); - const makerCollateralInfoPda = convergence - .collateral() - .pdas() - .collateralInfo({ - user: responseModel.maker, - programs, - }); - const takerCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: rfqModel.taker, - programs, - }); - const makerCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: responseModel.maker, - programs, - }); - const protocolCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: protocol.authority, - programs, - }); - - takerCollateralInfo = takerCollateralInfo ?? takerCollateralInfoPda; - makerCollateralInfo = makerCollateralInfo ?? makerCollateralInfoPda; - takerCollateralTokens = takerCollateralTokens ?? takerCollateralTokensPda; - makerCollateralTokens = makerCollateralTokens ?? makerCollateralTokensPda; - protocolCollateralTokens = - protocolCollateralTokens ?? protocolCollateralTokensPda; - - return TransactionBuilder.make() - .setFeePayer(payer) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createSettleOnePartyDefaultInstruction( - { - protocol: protocol.address, - rfq, - response, - takerCollateralInfo, - makerCollateralInfo, - takerCollateralTokens, - makerCollateralTokens, - protocolCollateralTokens, - tokenProgram: tokenProgram.address, - }, - rfqProgram.address - ), - signers: [], - key: 'settleOnePartyDefault', - }); -}; diff --git a/packages/js/src/plugins/rfqModule/operations/settleTwoPartyDefault.ts b/packages/js/src/plugins/rfqModule/operations/settleTwoPartyDefault.ts deleted file mode 100644 index c46c27ea1..000000000 --- a/packages/js/src/plugins/rfqModule/operations/settleTwoPartyDefault.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { createSettleTwoPartyDefaultInstruction } from '@convergence-rfq/rfq'; -import { PublicKey } from '@solana/web3.js'; - -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { Convergence } from '../../../Convergence'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, - makeConfirmOptionsFinalizedOnMainnet, -} from '../../../types'; -import { - TransactionBuilder, - TransactionBuilderOptions, -} from '../../../utils/TransactionBuilder'; -import { protocolCache } from '../../protocolModule/cache'; - -const Key = 'SettleTwoPartyDefaultOperation' as const; - -/** - * Settles two party default. - * - * ```ts - * await convergence - * .rfqs() - * .settleTwoPartyDefault({ address }; - * ``` - * - * @group Operations - * @category Constructors - */ -export const settleTwoPartyDefaultOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type SettleTwoPartyDefaultOperation = Operation< - typeof Key, - SettleTwoPartyDefaultInput, - SettleTwoPartyDefaultOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type SettleTwoPartyDefaultInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The address of the RFQ account. */ - rfq: PublicKey; - - /** The address of the response account. */ - response: PublicKey; - - /** - * Optional address of the taker collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: rfq.taker })` - * - */ - takerCollateralInfo?: PublicKey; - - /** - * Optional address of the Maker's collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: response.maker })` - * - */ - makerCollateralInfo?: PublicKey; - - /** - * Optional address of the Taker's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: rfq.taker, - * })` - */ - takerCollateralTokens?: PublicKey; - - /** - * Optional address of the Maker's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: response.maker, - * })` - */ - makerCollateralTokens?: PublicKey; - - /** - * Optional address of the DAO's collateral tokens account. - * - * @defaultValue `convergence.collateral().pdas(). - * collateralTokens({ - * user: dao - * })` - */ - protocolCollateralTokens?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type SettleTwoPartyDefaultOutput = { - /** The blockchain response from sending and confirming the transaction. */ - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ -export const settleTwoPartyDefaultOperationHandler: OperationHandler = - { - handle: async ( - operation: SettleTwoPartyDefaultOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const builder = await settleTwoPartyDefaultBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - scope.throwIfCanceled(); - - const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( - convergence, - scope.confirmOptions - ); - - const output = await builder.sendAndConfirm(convergence, confirmOptions); - scope.throwIfCanceled(); - - return { ...output }; - }, - }; - -/** - * @group Transaction Builders - * @category Inputs - */ -export type SettleTwoPartyDefaultBuilderParams = SettleTwoPartyDefaultInput; - -/** - * Settles two party default - * - * ```ts - * const transactionBuilder = convergence - * .rfqs() - * .builders() - * .settleTwoPartyDefault({ address }); - * ``` - * - * @group Transaction Builders - * @category Constructors - */ -export const settleTwoPartyDefaultBuilder = async ( - convergence: Convergence, - params: SettleTwoPartyDefaultBuilderParams, - options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { rfq, response } = params; - - const rfqProgram = convergence.programs().getRfq(programs); - const tokenProgram = convergence.programs().getToken(programs); - - const protocol = await protocolCache.get(convergence); - - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); - - let { - takerCollateralInfo, - makerCollateralInfo, - takerCollateralTokens, - makerCollateralTokens, - protocolCollateralTokens, - } = params; - - const takerCollateralInfoPda = convergence - .collateral() - .pdas() - .collateralInfo({ - user: rfqModel.taker, - programs, - }); - const makerCollateralInfoPda = convergence - .collateral() - .pdas() - .collateralInfo({ - user: responseModel.maker, - programs, - }); - const takerCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: rfqModel.taker, - programs, - }); - const makerCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: responseModel.maker, - programs, - }); - const protocolCollateralTokensPda = convergence - .collateral() - .pdas() - .collateralToken({ - user: protocol.authority, - programs, - }); - - takerCollateralInfo = takerCollateralInfo ?? takerCollateralInfoPda; - makerCollateralInfo = makerCollateralInfo ?? makerCollateralInfoPda; - takerCollateralTokens = takerCollateralTokens ?? takerCollateralTokensPda; - makerCollateralTokens = makerCollateralTokens ?? makerCollateralTokensPda; - protocolCollateralTokens = - protocolCollateralTokens ?? protocolCollateralTokensPda; - - return TransactionBuilder.make() - .setFeePayer(payer) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createSettleTwoPartyDefaultInstruction( - { - protocol: protocol.address, - rfq, - response, - takerCollateralInfo, - makerCollateralInfo, - takerCollateralTokens, - makerCollateralTokens, - protocolCollateralTokens, - tokenProgram: tokenProgram.address, - }, - rfqProgram.address - ), - signers: [], - key: 'settleTwoPartyDefault', - }); -}; diff --git a/packages/js/src/plugins/rfqModule/operations/unlockResponseCollateral.ts b/packages/js/src/plugins/rfqModule/operations/unlockResponseCollateral.ts deleted file mode 100644 index f1a74f0c9..000000000 --- a/packages/js/src/plugins/rfqModule/operations/unlockResponseCollateral.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; -import { createUnlockResponseCollateralInstruction } from '@convergence-rfq/rfq'; - -import { - Operation, - OperationHandler, - OperationScope, - useOperation, -} from '../../../types'; -import { Convergence } from '../../../Convergence'; -import { - TransactionBuilder, - TransactionBuilderOptions, -} from '../../../utils/TransactionBuilder'; -import { protocolCache } from '../../protocolModule/cache'; -import { SendAndConfirmTransactionResponse } from '@/plugins'; - -const Key = 'unlockResponseCollateralOperation' as const; - -/** - * Unlocks collateral for a Response - * - * ```ts - * await convergence - * .rfqs() - * .unlockResponseCollateral({ - * response: , - * }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const unlockResponseCollateralOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type UnlockResponseCollateralOperation = Operation< - typeof Key, - UnlockResponseCollateralInput, - UnlockResponseCollateralOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type UnlockResponseCollateralInput = { - /** - * The response address. - */ - response: PublicKey; - - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type UnlockResponseCollateralOutput = { - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ -export const unlockResponseCollateralOperationHandler: OperationHandler = - { - handle: async ( - operation: UnlockResponseCollateralOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const builder = await unlockResponseCollateralBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - - const output = await builder.sendAndConfirm( - convergence, - scope.confirmOptions - ); - scope.throwIfCanceled(); - - return output; - }, - }; - -export type UnlockResponseCollateralBuilderParams = - UnlockResponseCollateralInput; - -/** - * UnlockRfqs a collateral account. - * - * ```ts - * const transactionBuilder = await convergence - * .rfqs() - * .builders() - * .unlockResponseCollateral(); - * ``` - * - * @group Transaction Builders - * @category Constructors - */ -export const unlockResponseCollateralBuilder = async ( - convergence: Convergence, - params: UnlockResponseCollateralBuilderParams, - options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { response } = params; - - const protocol = await protocolCache.get(convergence); - - const responseModel = await convergence - .rfqs() - .findResponseByAddress({ address: response }); - - const { taker } = await convergence - .rfqs() - .findRfqByAddress({ address: responseModel.rfq }); - - return TransactionBuilder.make() - .setFeePayer(payer) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createUnlockResponseCollateralInstruction( - { - rfq: responseModel.rfq, - response: responseModel.address, - protocol: convergence.protocol().pdas().protocol(), - takerCollateralInfo: convergence.collateral().pdas().collateralInfo({ - user: taker, - programs, - }), - makerCollateralInfo: convergence.collateral().pdas().collateralInfo({ - user: responseModel.maker, - programs, - }), - takerCollateralTokens: convergence - .collateral() - .pdas() - .collateralToken({ - user: taker, - programs, - }), - makerCollateralTokens: convergence - .collateral() - .pdas() - .collateralToken({ - user: responseModel.maker, - programs, - }), - protocolCollateralTokens: convergence - .collateral() - .pdas() - .collateralToken({ - user: protocol.authority, - programs, - }), - }, - convergence.programs().getRfq(programs).address - ), - signers: [], - key: 'unlockeResponseCollateral', - }); -}; diff --git a/packages/js/src/plugins/rfqModule/operations/unlockResponsesCollateral.ts b/packages/js/src/plugins/rfqModule/operations/unlockResponsesCollateral.ts deleted file mode 100644 index 682c7cccc..000000000 --- a/packages/js/src/plugins/rfqModule/operations/unlockResponsesCollateral.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; - -import { - Operation, - OperationHandler, - OperationScope, - useOperation, -} from '../../../types'; -import { Convergence } from '../../../Convergence'; -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { unlockResponseCollateralBuilder } from './unlockResponseCollateral'; - -const Key = 'unlockResponsesCollateralOperation' as const; - -/** - * Unlocks collateral for a Response - * - * ```ts - * await convergence - * .rfqs() - * .unlockResponseCollateral({ - * responses: [], - * }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const unlockResponsesCollateralOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type UnlockResponsesCollateralOperation = Operation< - typeof Key, - UnlockResponsesCollateralInput, - UnlockResponsesCollateralOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type UnlockResponsesCollateralInput = { - /** - * The response address. - */ - responses: PublicKey[]; - - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type UnlockResponsesCollateralOutput = { - responses: SendAndConfirmTransactionResponse[]; -}; - -/** - * @group Operations - * @category Handlers - */ -export const unlockResponsesCollateralOperationHandler: OperationHandler = - { - handle: async ( - operation: UnlockResponsesCollateralOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const { responses: rfqResponses } = operation.input; - - const builders = await Promise.all( - rfqResponses.map((response) => - unlockResponseCollateralBuilder( - convergence, - { response, ...operation.input }, - scope - ) - ) - ); - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTxs = await convergence - .identity() - .signAllTransactions( - builders.map((b) => b.toTransaction(lastValidBlockHeight)) - ); - - const responses = await Promise.all( - signedTxs.map((signedTx) => - convergence - .rpc() - .serializeAndSendTransaction( - signedTx, - lastValidBlockHeight, - scope.confirmOptions - ) - ) - ); - scope.throwIfCanceled(); - - return { responses }; - }, - }; diff --git a/packages/js/src/plugins/rfqModule/operations/unlockRfqCollateral.ts b/packages/js/src/plugins/rfqModule/operations/unlockRfqCollateral.ts deleted file mode 100644 index 200d0e6f6..000000000 --- a/packages/js/src/plugins/rfqModule/operations/unlockRfqCollateral.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; -import { createUnlockRfqCollateralInstruction } from '@convergence-rfq/rfq'; - -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, -} from '../../../types'; -import { Convergence } from '../../../Convergence'; -import { - TransactionBuilder, - TransactionBuilderOptions, -} from '../../../utils/TransactionBuilder'; - -const Key = 'UnlockRfqCollateralOperation' as const; - -/** - * Unlocks collateral for an Rfq - * - * ```ts - * const rfq = await convergence - * .rfqs() - * .unlockRfqCollateral({ rfq: rfq.address }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const unlockRfqCollateralOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type UnlockRfqCollateralOperation = Operation< - typeof Key, - UnlockRfqCollateralInput, - UnlockRfqCollateralOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type UnlockRfqCollateralInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The address of the Rfq account. */ - rfq: PublicKey; - - /** - * Optional address of the Taker's collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: rfq.taker })` - * - */ - collateralInfo?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type UnlockRfqCollateralOutput = { - response: SendAndConfirmTransactionResponse; -}; - -/** - * @group Operations - * @category Handlers - */ -export const unlockRfqCollateralOperationHandler: OperationHandler = - { - handle: async ( - operation: UnlockRfqCollateralOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const builder = await unlockRfqCollateralBuilder( - convergence, - { - ...operation.input, - }, - scope - ); - - const output = await builder.sendAndConfirm( - convergence, - scope.confirmOptions - ); - scope.throwIfCanceled(); - - return output; - }, - }; - -export type UnlockRfqCollateralBuilderParams = UnlockRfqCollateralInput; - -/** - * @group Transaction Builders - * @category Contexts - */ -export type UnlockRfqCollateralBuilderContext = - SendAndConfirmTransactionResponse; - -/** - * UnlockRfqs a collateral account. - * - * ```ts - * const transactionBuilder = await convergence - * .rfqs() - * .builders() - * .unlockRfqCollateral(); - * ``` - * - * @group Transaction Builders - * @category Constructors - */ -export const unlockRfqCollateralBuilder = async ( - convergence: Convergence, - params: UnlockRfqCollateralBuilderParams, - options: TransactionBuilderOptions = {} -): Promise => { - const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { rfq } = params; - - let { collateralInfo } = params; - - const rfqProgram = convergence.programs().getRfq(programs); - - const rfqModel = await convergence.rfqs().findRfqByAddress({ address: rfq }); - - const collateralInfoPda = convergence.collateral().pdas().collateralInfo({ - user: rfqModel.taker, - programs, - }); - - collateralInfo = collateralInfo ?? collateralInfoPda; - - return TransactionBuilder.make() - .setFeePayer(payer) - .addTxPriorityFeeIx(convergence) - .add({ - instruction: createUnlockRfqCollateralInstruction( - { - protocol: convergence.protocol().pdas().protocol(), - rfq, - collateralInfo, - }, - rfqProgram.address - ), - signers: [], - key: 'unlockRfqCollateral', - }); -}; diff --git a/packages/js/src/plugins/rfqModule/operations/unlockRfqsCollateral.ts b/packages/js/src/plugins/rfqModule/operations/unlockRfqsCollateral.ts deleted file mode 100644 index 720409a95..000000000 --- a/packages/js/src/plugins/rfqModule/operations/unlockRfqsCollateral.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { PublicKey } from '@solana/web3.js'; -import { - Operation, - OperationHandler, - OperationScope, - useOperation, -} from '../../../types'; -import { Convergence } from '../../../Convergence'; -import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { unlockRfqCollateralBuilder } from './unlockRfqCollateral'; - -const Key = 'UnlockRfqsCollateralOperation' as const; - -/** - * Unlocks collateral for multiples Rfqs - * - * ```ts - * const rfq = await convergence - * .rfqs() - * .unlockRfqsCollateral({ rfqs: [rfq.address, rfq2.address,...] }); - * ``` - * - * @group Operations - * @category Constructors - */ -export const unlockRfqsCollateralOperation = - useOperation(Key); - -/** - * @group Operations - * @category Types - */ -export type UnlockRfqsCollateralOperation = Operation< - typeof Key, - UnlockRfqsCollateralInput, - UnlockRfqsCollateralOutput ->; - -/** - * @group Operations - * @category Inputs - */ -export type UnlockRfqsCollateralInput = { - /** - * The protocol address. - * - * @defaultValue `convergence.protocol().pdas().protocol()` - */ - protocol?: PublicKey; - - /** The address of the Rfq account. */ - rfqs: PublicKey[]; - - /** - * Optional address of the Taker's collateral info account. - * - * @defaultValue `convergence.collateral().pdas().collateralInfo({ user: rfq.taker })` - * - */ - collateralInfo?: PublicKey; -}; - -/** - * @group Operations - * @category Outputs - */ -export type UnlockRfqsCollateralOutput = { - responses: SendAndConfirmTransactionResponse[]; -}; - -/** - * @group Operations - * @category Handlers - */ -export const unlockRfqsCollateralOperationHandler: OperationHandler = - { - handle: async ( - operation: UnlockRfqsCollateralOperation, - convergence: Convergence, - scope: OperationScope - ): Promise => { - const { rfqs } = operation.input; - const builders = await Promise.all( - rfqs.map((rfq) => - unlockRfqCollateralBuilder( - convergence, - { - ...operation.input, - rfq, - }, - scope - ) - ) - ); - - const lastValidBlockHeight = await convergence.rpc().getLatestBlockhash(); - const signedTxs = await convergence - .identity() - .signAllTransactions( - builders.map((b) => b.toTransaction(lastValidBlockHeight)) - ); - - const responses = await Promise.all( - signedTxs.map((signedTx) => - convergence - .rpc() - .serializeAndSendTransaction( - signedTx, - lastValidBlockHeight, - scope.confirmOptions - ) - ) - ); - scope.throwIfCanceled(); - - return { responses }; - }, - }; diff --git a/packages/js/src/plugins/rfqModule/plugin.ts b/packages/js/src/plugins/rfqModule/plugin.ts index ef9d2b5a0..0a54d8e3e 100644 --- a/packages/js/src/plugins/rfqModule/plugin.ts +++ b/packages/js/src/plugins/rfqModule/plugin.ts @@ -37,42 +37,30 @@ import { findRfqByAddressOperationHandler, findRfqsOperation, findRfqsOperationHandler, - partiallySettleLegsOperation, - partiallySettleLegsOperationHandler, prepareMoreLegsSettlementOperation, prepareMoreLegsSettlementOperationHandler, partlyRevertSettlementPreparationOperation, partlyRevertSettlementPreparationOperationHandler, - partiallySettleLegsAndSettleOperation, - partiallySettleLegsAndSettleOperationHandler, prepareSettlementOperation, prepareSettlementOperationHandler, prepareSettlementAndPrepareMoreLegsOperation, prepareSettlementAndPrepareMoreLegsOperationHandler, settleOperation, settleOperationHandler, - settleOnePartyDefaultOperation, - settleOnePartyDefaultOperationHandler, - settleTwoPartyDefaultOperation, - settleTwoPartyDefaultOperationHandler, - unlockRfqCollateralOperation, - unlockRfqCollateralOperationHandler, createAndFinalizeRfqConstructionOperation, createAndFinalizeRfqConstructionOperationHandler, cancelRfqsOperation, cancelRfqsOperationHandler, cancelResponsesOperation, cancelResponsesOperationHandler, - unlockResponseCollateralOperation, - unlockResponseCollateralOperationHandler, - unlockResponsesCollateralOperation, - unlockResponsesCollateralOperationHandler, - unlockRfqsCollateralOperation, - unlockRfqsCollateralOperationHandler, cleanUpRfqsOperation, cleanUpRfqsOperationHandler, getSettlementResultOperation, getSettlementResultHandler, + createPrintTradeRfqOperation, + createPrintTradeRfqOperationHandler, + preparePrintTradeSettlementOperationHandler, + preparePrintTradeSettlementOperation, getResponseStateAndActionOperation, getResponseStateAndActionHandler, } from './operations'; @@ -114,6 +102,10 @@ export const rfqModule = (): ConvergencePlugin => ({ createAndFinalizeRfqConstructionOperation, createAndFinalizeRfqConstructionOperationHandler ); + op.register( + createPrintTradeRfqOperation, + createPrintTradeRfqOperationHandler + ); op.register( finalizeRfqConstructionOperation, finalizeRfqConstructionOperationHandler @@ -132,10 +124,6 @@ export const rfqModule = (): ConvergencePlugin => ({ ); op.register(findRfqByAddressOperation, findRfqByAddressOperationHandler); op.register(findRfqsOperation, findRfqsOperationHandler); - op.register( - partiallySettleLegsOperation, - partiallySettleLegsOperationHandler - ); op.register( partlyRevertSettlementPreparationOperation, partlyRevertSettlementPreparationOperationHandler @@ -145,48 +133,20 @@ export const rfqModule = (): ConvergencePlugin => ({ prepareMoreLegsSettlementOperationHandler ); op.register(prepareSettlementOperation, prepareSettlementOperationHandler); - op.register(respondToRfqOperation, respondToRfqOperationHandler); - op.register(settleOperation, settleOperationHandler); - op.register( - settleOnePartyDefaultOperation, - settleOnePartyDefaultOperationHandler - ); - op.register( - settleTwoPartyDefaultOperation, - settleTwoPartyDefaultOperationHandler - ); - op.register( - unlockResponseCollateralOperation, - unlockResponseCollateralOperationHandler - ); op.register( - unlockRfqCollateralOperation, - unlockRfqCollateralOperationHandler + preparePrintTradeSettlementOperation, + preparePrintTradeSettlementOperationHandler ); + op.register(respondToRfqOperation, respondToRfqOperationHandler); + op.register(settleOperation, settleOperationHandler); op.register( prepareSettlementAndPrepareMoreLegsOperation, prepareSettlementAndPrepareMoreLegsOperationHandler ); - op.register( - partiallySettleLegsAndSettleOperation, - partiallySettleLegsAndSettleOperationHandler - ); op.register(cancelRfqsOperation, cancelRfqsOperationHandler); op.register(cancelResponsesOperation, cancelResponsesOperationHandler); op.register(cleanUpResponseOperation, cleanUpResponseOperationHandler); op.register(cleanUpRfqsOperation, cleanUpRfqsOperationHandler); - op.register( - unlockResponseCollateralOperation, - unlockResponseCollateralOperationHandler - ); - op.register( - unlockResponsesCollateralOperation, - unlockResponsesCollateralOperationHandler - ); - op.register( - unlockRfqsCollateralOperation, - unlockRfqsCollateralOperationHandler - ); op.register(getSettlementResultOperation, getSettlementResultHandler); op.register( getResponseStateAndActionOperation, diff --git a/packages/js/src/plugins/riskEngineModule/clientCollateralCalculator.ts b/packages/js/src/plugins/riskEngineModule/clientCollateralCalculator.ts index 297e8b5ee..b35d56865 100644 --- a/packages/js/src/plugins/riskEngineModule/clientCollateralCalculator.ts +++ b/packages/js/src/plugins/riskEngineModule/clientCollateralCalculator.ts @@ -1,7 +1,6 @@ import { RiskCategory } from '@convergence-rfq/rfq'; import { futureCommonDataBeet, - InstrumentType, optionCommonDataBeet, OptionType, RiskCategoryInfo, @@ -12,13 +11,14 @@ import { Commitment, PublicKey } from '@solana/web3.js'; import { blackScholes } from 'black-scholes'; import { Convergence } from '../../Convergence'; -import { toSolitaRiskCategory } from '../protocolModule'; +import { toPriceOracle, toSolitaRiskCategory } from '../protocolModule'; import { LegInstrument } from '../instrumentModule'; import { AuthoritySide } from '../rfqModule/models/AuthoritySide'; +import { PrintTradeLeg } from '../printTradeModule'; import { ResponseSide } from '../rfqModule'; import { AggregatorAccount } from './switchboard/aggregatorAccount'; import { AggregatorAccountData } from './switchboard/types/aggregatorAccountData'; -import { Config } from './models'; +import { Config, InstrumentType } from './models'; import { FUTURE_UNDERLYING_AMOUNT_PER_CONTRACT_DECIMALS, SETTLEMENT_WINDOW_BREAKPOINS, @@ -59,7 +59,7 @@ type LegInfo = { export async function calculateRisk( convergence: Convergence, config: Config, - legs: LegInstrument[], + legs: LegInstrument[] | PrintTradeLeg[], cases: CalculationCase[], settlementPeriod: number, commitment?: Commitment @@ -72,24 +72,33 @@ export async function calculateRisk( fetchBaseAssetInfo(convergence, id, commitment) ) ); - const instrumentTypesMapping = config.instrumentTypes; - const legInfos = legs.map((leg) => { + const legInfos: LegInfo[] = legs.map((leg) => { let amount = leg.getAmount(); if (leg.getSide() == 'long') { amount = -amount; } - const assetType = instrumentTypesMapping.find((entry) => - entry.program.equals(leg.getProgramId()) - )?.rType; + let assetType: InstrumentType; + if (leg.legType === 'printTrade') { + assetType = leg.getInstrumentType(); + } else { + const escrowAssetType = config.instrumentTypes[leg.getInstrumentIndex()]; + if (escrowAssetType === null) { + throw new Error( + `Instrument index ${leg.getInstrumentIndex()} is not registered in the risk engine` + ); + } - if (assetType === undefined) { - throw Error( - `Instrument ${leg - .getProgramId() - .toString()} is missing from risk engine config!` - ); + if (escrowAssetType === undefined) { + throw Error( + `Instrument ${leg + .getProgramId() + .toString()} is missing from risk engine config!` + ); + } + + assetType = escrowAssetType; } return { @@ -156,16 +165,22 @@ async function fetchBaseAssetInfo( const baseAsset = await convergence .protocol() .findBaseAssetByAddress({ address }); + const priceOracle = toPriceOracle(baseAsset); - if (!baseAsset.priceOracle.address) { - throw new Error('Price oracle address is missing'); - } + let price: number; - const price = await fetchLatestOraclePrice( - convergence, - baseAsset.priceOracle.address, - commitment - ); + if (priceOracle.price !== undefined) { + price = priceOracle.price; + } else { + if (priceOracle.address === undefined) { + throw Error('Price oracle address is missing'); + } + price = await fetchLatestOraclePrice( + convergence, + priceOracle.address, + commitment + ); + } return { index: baseAssetIndex, @@ -323,23 +338,23 @@ function calculateAssetUnitValue( interestRate: number ): number { switch (leg.instrumentType) { - case InstrumentType.Spot: + case 'spot': return price; - case InstrumentType.TermFuture: - case InstrumentType.PerpFuture: + case 'term-future': + case 'perp-future': const [futureCommonData] = futureCommonDataBeet.deserialize(leg.data); const amountPerContract = Number(futureCommonData.underlyingAmountPerContract) / 10 ** FUTURE_UNDERLYING_AMOUNT_PER_CONTRACT_DECIMALS; return price * amountPerContract; - case InstrumentType.Option: + case 'option': const [optionCommonData] = optionCommonDataBeet.deserialize(leg.data); const optionType = optionCommonData.optionType == OptionType.Call ? 'call' : 'put'; const underlyingAmountPerContract = Number(optionCommonData.underlyingAmountPerContract) / - 10 ** optionCommonData.underlyingAmoundPerContractDecimals; + 10 ** optionCommonData.underlyingAmountPerContractDecimals; const strikePrice = Number(optionCommonData.strikePrice) / @@ -374,8 +389,7 @@ function selectScenarios( settlementPeriod: number ): Scenario[] { const haveOptionLegs = - legs.filter((leg) => leg.instrumentType == InstrumentType.Option).length > - 0; + legs.filter((leg) => leg.instrumentType === 'option').length > 0; const getScenarioIndex = (settlementPeriod: number) => { for (let i = 0; i < SETTLEMENT_WINDOW_BREAKPOINS.length; i++) { diff --git a/packages/js/src/plugins/riskEngineModule/constants.ts b/packages/js/src/plugins/riskEngineModule/constants.ts index 656385178..3ca19f761 100644 --- a/packages/js/src/plugins/riskEngineModule/constants.ts +++ b/packages/js/src/plugins/riskEngineModule/constants.ts @@ -2,21 +2,21 @@ import { RiskCategoryInfo, Scenario } from '@convergence-rfq/risk-engine'; import { toBigNumber as tbn } from '../../types'; -export const DEFAULT_MIN_COLLATERAL_REQUIREMENT = tbn(1_000_000_000); +export const DEFAULT_MIN_COLLATERAL_REQUIREMENT = tbn(0); -export const DEFAULT_COLLATERAL_FOR_FIXED_QUOTE_AMOUNT_RFQ = tbn(2_000_000_000); +export const DEFAULT_COLLATERAL_FOR_FIXED_QUOTE_AMOUNT_RFQ = tbn(0); export const DEFAULT_MINT_DECIMALS = 9; -export const DEFAULT_SAFETY_PRICE_SHIFT_FACTOR = 0.01; +export const DEFAULT_SAFETY_PRICE_SHIFT_FACTOR = 0; -export const DEFAULT_OVERALL_SAFETY_FACTOR = 0.1; +export const DEFAULT_OVERALL_SAFETY_FACTOR = 0; -export const DEFAULT_ORACLE_STALENESS = 300; +export const DEFAULT_ORACLE_STALENESS = 60 * 60 * 24 * 365 * 10; export const DEFAULT_ACCEPTED_ORACLE_CONFIDENCE_INTERVAL_POSITION = 0.1; -export const DEFAULT_ACCEPTED_ORACLE_STALENESS = 300; +export const DEFAULT_ACCEPTED_ORACLE_STALENESS = 60 * 60 * 24 * 365 * 10; export const DEFAULT_ACCEPTED_ORACLE_CONFIDENCE_INTERVAL_PORTION = 0.01; export const SETTLEMENT_WINDOW_PEDIODS = 6; @@ -33,45 +33,45 @@ export const OPTION_UNDERLYING_AMOUNT_PER_CONTRACT_DECIMALS = 9; export const OPTION_STRIKE_PRICE_DECIMALS = 9; export const DEFAULT_RISK_CATEGORIES_INFO = { - veryLow: toRiskCategoryInfo(0.05, 0.5, [ - toScenario(0.02, 0.2), - toScenario(0.04, 0.3), - toScenario(0.08, 0.4), - toScenario(0.12, 0.5), - toScenario(0.2, 0.6), - toScenario(0.3, 0.7), + veryLow: toRiskCategoryInfo(0, 0, [ + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), ]), - low: toRiskCategoryInfo(0.05, 0.8, [ - toScenario(0.04, 0.4), - toScenario(0.08, 0.6), - toScenario(0.16, 0.8), - toScenario(0.24, 1), - toScenario(0.4, 1.2), - toScenario(0.6, 1.4), + low: toRiskCategoryInfo(0, 0, [ + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), ]), - medium: toRiskCategoryInfo(0.05, 1.2, [ - toScenario(0.06, 0.6), - toScenario(0.12, 0.9), - toScenario(0.24, 1.2), - toScenario(0.36, 1.5), - toScenario(0.6, 1.8), - toScenario(0.9, 2.1), + medium: toRiskCategoryInfo(0, 0, [ + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), ]), - high: toRiskCategoryInfo(0.05, 2.4, [ - toScenario(0.08, 0.8), - toScenario(0.16, 1.2), - toScenario(0.32, 1.6), - toScenario(0.48, 2), - toScenario(0.8, 2.4), - toScenario(1.2, 2.8), + high: toRiskCategoryInfo(0, 0, [ + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), ]), - veryHigh: toRiskCategoryInfo(0.05, 5, [ - toScenario(0.1, 1), - toScenario(0.2, 1.5), - toScenario(0.4, 2), - toScenario(0.6, 2.5), - toScenario(1, 3), - toScenario(1.5, 3.5), + veryHigh: toRiskCategoryInfo(0, 0, [ + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), + toScenario(0, 0), ]), }; diff --git a/packages/js/src/plugins/riskEngineModule/helpers.ts b/packages/js/src/plugins/riskEngineModule/helpers.ts new file mode 100644 index 000000000..bbe644d27 --- /dev/null +++ b/packages/js/src/plugins/riskEngineModule/helpers.ts @@ -0,0 +1,42 @@ +import { AccountMeta, PublicKey } from '@solana/web3.js'; +import { LegInstrument } from '../instrumentModule'; +import { PrintTradeLeg } from '../printTradeModule'; +import { toPriceOracle } from '../protocolModule'; +import { Convergence } from '@/Convergence'; + +export async function getRiskEngineAccounts( + cvg: Convergence, + legs: LegInstrument[] | PrintTradeLeg[] +): Promise { + const configAddress = cvg.riskEngine().pdas().config(); + + const baseAssetIndexSet: Set = new Set( + legs.map((leg) => leg.getBaseAssetIndex().value) + ); + const uniqueBaseAssetIndexes = Array.from(baseAssetIndexSet); + + const baseAssetAddresses = uniqueBaseAssetIndexes.map((value) => + cvg.protocol().pdas().baseAsset({ index: value }) + ); + + const oracleInfos = await Promise.all( + baseAssetAddresses.map(async (baseAsset) => + cvg.protocol().findBaseAssetByAddress({ address: baseAsset }) + ) + ); + const oracleAddresses = oracleInfos + .map((oracleInfo) => toPriceOracle(oracleInfo).address) + .filter((address): address is PublicKey => address !== undefined); + + const allAddresses = [ + configAddress, + ...baseAssetAddresses, + ...oracleAddresses, + ]; + + return allAddresses.map((address) => ({ + pubkey: address, + isSigner: false, + isWritable: false, + })); +} diff --git a/packages/js/src/plugins/riskEngineModule/models/Config.ts b/packages/js/src/plugins/riskEngineModule/models/Config.ts index 438106e22..f84a8d99a 100644 --- a/packages/js/src/plugins/riskEngineModule/models/Config.ts +++ b/packages/js/src/plugins/riskEngineModule/models/Config.ts @@ -3,12 +3,13 @@ import { RiskCategoryChange as SolitaRiskCategoryChange } from '@convergence-rfq import { bignum } from '@convergence-rfq/beet'; import { ConfigAccount } from '../accounts'; -import { RiskCategoryInfo, InstrumentInfo } from '../types'; +import { RiskCategoryInfo } from '../types'; import { assert } from '../../../utils/assert'; import { RiskCategory, toSolitaRiskCategory, } from '../../protocolModule/models'; +import { InstrumentType, fromSolitaInstrumentType } from './InstrumentType'; /** * This model captures all the relevant information about a Risk Engine Config @@ -42,7 +43,7 @@ export type Config = { readonly riskCategoriesInfo: RiskCategoryInfo[]; /** The instrument types info. */ - readonly instrumentTypes: InstrumentInfo[]; + readonly instrumentTypes: (InstrumentType | null)[]; }; export type RiskCategoryChange = { @@ -83,5 +84,7 @@ export const toConfig = (account: ConfigAccount): Config => ({ safetyPriceShiftFactor: account.data.safetyPriceShiftFactor, overallSafetyFactor: account.data.overallSafetyFactor, riskCategoriesInfo: account.data.riskCategoriesInfo, - instrumentTypes: account.data.instrumentTypes, + instrumentTypes: account.data.instrumentTypes.map((instrumentType) => + fromSolitaInstrumentType(instrumentType) + ), }); diff --git a/packages/js/src/plugins/riskEngineModule/models/InstrumentType.ts b/packages/js/src/plugins/riskEngineModule/models/InstrumentType.ts new file mode 100644 index 000000000..1113bf246 --- /dev/null +++ b/packages/js/src/plugins/riskEngineModule/models/InstrumentType.ts @@ -0,0 +1,85 @@ +import { + StoredInstrumentType as SolitaStoredInstrumentType, + InstrumentType as SolitaInstrumentType, +} from '@convergence-rfq/risk-engine'; + +export type InstrumentType = 'spot' | 'option' | 'term-future' | 'perp-future'; + +export function fromSolitaInstrumentType( + instrumentType: SolitaStoredInstrumentType +): InstrumentType | null { + switch (instrumentType) { + case SolitaStoredInstrumentType.Missing: { + return null; + } + case SolitaStoredInstrumentType.Spot: { + return 'spot'; + } + case SolitaStoredInstrumentType.Option: { + return 'option'; + } + case SolitaStoredInstrumentType.PerpFuture: { + return 'perp-future'; + } + case SolitaStoredInstrumentType.TermFuture: { + return 'term-future'; + } + } +} + +export function toSolitaInstrumentType( + instrumentType: InstrumentType +): SolitaInstrumentType { + switch (instrumentType) { + case 'spot': { + return SolitaInstrumentType.Spot; + } + case 'option': { + return SolitaInstrumentType.Option; + } + case 'perp-future': { + return SolitaInstrumentType.PerpFuture; + } + case 'term-future': { + return SolitaInstrumentType.TermFuture; + } + } +} + +export function toNumberInstrumentType(instrumentType: InstrumentType): number { + switch (instrumentType) { + case 'spot': { + return 1; + } + case 'option': { + return 2; + } + case 'term-future': { + return 3; + } + case 'perp-future': { + return 4; + } + } +} + +export function fromNumberInstrumentType( + instrumentType: number +): InstrumentType { + switch (instrumentType) { + case 1: { + return 'spot'; + } + case 2: { + return 'option'; + } + case 3: { + return 'term-future'; + } + case 4: { + return 'perp-future'; + } + default: + throw new Error('Invalid instrument type!'); + } +} diff --git a/packages/js/src/plugins/riskEngineModule/models/index.ts b/packages/js/src/plugins/riskEngineModule/models/index.ts index bd37f302d..aabad9298 100644 --- a/packages/js/src/plugins/riskEngineModule/models/index.ts +++ b/packages/js/src/plugins/riskEngineModule/models/index.ts @@ -1 +1,2 @@ export * from './Config'; +export * from './InstrumentType'; diff --git a/packages/js/src/plugins/riskEngineModule/operations/calculateCollateralForRfq.ts b/packages/js/src/plugins/riskEngineModule/operations/calculateCollateralForRfq.ts index a9ce092ee..de60fc0d5 100644 --- a/packages/js/src/plugins/riskEngineModule/operations/calculateCollateralForRfq.ts +++ b/packages/js/src/plugins/riskEngineModule/operations/calculateCollateralForRfq.ts @@ -12,12 +12,10 @@ import { useOperation, } from '../../../types'; import { Convergence } from '../../../Convergence'; -import { - LegInstrument, - QuoteInstrument, -} from '../../../plugins/instrumentModule'; +import { LegInstrument } from '../../../plugins/instrumentModule'; import { removeDecimals } from '../../../utils/conversions'; import { FixedSize, OrderType, ResponseSide } from '../../../plugins/rfqModule'; +import { PrintTradeLeg } from '@/plugins/printTradeModule'; const Key = 'CalculateCollateralForRfqOperation' as const; @@ -80,12 +78,7 @@ export type CalculateCollateralForRfqInput = { /** * Legs of the RFQ being created. */ - legs: LegInstrument[]; - - /** - * Quote asset of the RFQ being created. - */ - quoteAsset: QuoteInstrument; + legs: LegInstrument[] | PrintTradeLeg[]; /** * Settlement period of the RFQ being created in seconds. diff --git a/packages/js/src/plugins/riskEngineModule/operations/setInstrumentType.ts b/packages/js/src/plugins/riskEngineModule/operations/setInstrumentType.ts index b08a260f9..2a6116b74 100644 --- a/packages/js/src/plugins/riskEngineModule/operations/setInstrumentType.ts +++ b/packages/js/src/plugins/riskEngineModule/operations/setInstrumentType.ts @@ -1,9 +1,7 @@ import { createSetInstrumentTypeInstruction } from '@convergence-rfq/risk-engine'; -import { PublicKey } from '@solana/web3.js'; import { SendAndConfirmTransactionResponse } from '../../rpcModule'; -import { Config } from '../models'; -import { InstrumentType } from '../types'; +import { Config, InstrumentType, toSolitaInstrumentType } from '../models'; import { Convergence } from '../../../Convergence'; import { Operation, @@ -11,12 +9,14 @@ import { OperationScope, useOperation, Signer, + PublicKey, } from '../../../types'; import { TransactionBuilder, TransactionBuilderOptions, } from '../../../utils/TransactionBuilder'; import { riskEngineConfigCache } from '../cache'; +import { getInstrumentProgramIndex } from '@/plugins/instrumentModule'; const Key = 'SetInstrumentTypeOperation' as const; @@ -89,9 +89,16 @@ export const setInstrumentTypeOperationHandler: OperationHandler => { + const protocol = await convergence.protocol().get(); + const instrumentIndex = getInstrumentProgramIndex( + protocol, + operation.input.instrumentProgram + ); + const builder = setInstrumentTypeBuilder( convergence, operation.input, + instrumentIndex, scope ); @@ -129,10 +136,11 @@ export type SetInstrumentTypeBuilderParams = SetInstrumentTypeInput; export const setInstrumentTypeBuilder = ( convergence: Convergence, params: SetInstrumentTypeBuilderParams, + instrumentIndex: number, options: TransactionBuilderOptions = {} ): TransactionBuilder => { const { programs, payer = convergence.rpc().getDefaultFeePayer() } = options; - const { authority = payer, instrumentProgram, instrumentType } = params; + const { authority = payer, instrumentType } = params; const riskEngineProgram = convergence.programs().getRiskEngine(programs); @@ -150,8 +158,8 @@ export const setInstrumentTypeBuilder = ( config, }, { - instrumentProgram, - instrumentType, + instrumentIndex, + instrumentType: toSolitaInstrumentType(instrumentType), }, riskEngineProgram.address ), diff --git a/packages/js/src/plugins/riskEngineModule/types.ts b/packages/js/src/plugins/riskEngineModule/types.ts index 4d7470f91..85ffd1104 100644 --- a/packages/js/src/plugins/riskEngineModule/types.ts +++ b/packages/js/src/plugins/riskEngineModule/types.ts @@ -1,7 +1,2 @@ export { RiskCategory as SolitaRiskCatgory } from '@convergence-rfq/rfq'; -export type { - Scenario, - RiskCategoryInfo, - InstrumentInfo, -} from '@convergence-rfq/risk-engine'; -export { InstrumentType } from '@convergence-rfq/risk-engine'; +export type { Scenario, RiskCategoryInfo } from '@convergence-rfq/risk-engine'; diff --git a/packages/js/src/plugins/spotInstrumentModule/accounts.ts b/packages/js/src/plugins/spotInstrumentModule/accounts.ts new file mode 100644 index 000000000..6f59e7521 --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/accounts.ts @@ -0,0 +1,18 @@ +import { Config } from '@convergence-rfq/spot-instrument'; + +import { + Account, + getAccountParsingAndAssertingFunction, + getAccountParsingFunction, +} from '../../types'; + +/** @group Accounts */ +export type SpotInstrumentConfigAccount = Account; + +/** @group Account Helpers */ +export const parseSpotInstrumentConfigAccount = + getAccountParsingFunction(Config); + +/** @group Account Helpers */ +export const toSpotInstrumentConfigAccount = + getAccountParsingAndAssertingFunction(Config); diff --git a/packages/js/src/plugins/spotInstrumentModule/client.ts b/packages/js/src/plugins/spotInstrumentModule/client.ts new file mode 100644 index 000000000..c7e9a278b --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/client.ts @@ -0,0 +1,49 @@ +import { + InitializeSpotInstrumentConfigInput, + InitializeSpotInstrumentConfigOutput, + initializeSpotInstrumentConfigOperation, + ModifySpotInstrumentConfigInput, + ModifySpotInstrumentConfigOutput, + modifySpotInstrumentConfigOperation, + FetchSpotInstrumentConfigInput, + FetchSpotInstrumentConfigOutput, + fetchSpotInstrumentConfigOperation, +} from './operations'; +import { SpotInstrumentPdasClient } from './pdas'; +import { OperationOptions } from '@/types'; +import { Convergence } from '@/Convergence'; + +export class SpotInstrumentClient { + constructor(protected readonly cvg: Convergence) {} + + pdas() { + return new SpotInstrumentPdasClient(this.cvg); + } + + fetchConfig( + input?: FetchSpotInstrumentConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(fetchSpotInstrumentConfigOperation(input), options); + } + + initializeConfig( + input: InitializeSpotInstrumentConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(initializeSpotInstrumentConfigOperation(input), options); + } + + modifyConfig( + input: ModifySpotInstrumentConfigInput, + options?: OperationOptions + ): Promise { + return this.cvg + .operations() + .execute(modifySpotInstrumentConfigOperation(input), options); + } +} diff --git a/packages/js/src/plugins/spotInstrumentModule/constants.ts b/packages/js/src/plugins/spotInstrumentModule/constants.ts new file mode 100644 index 000000000..5eb879215 --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/constants.ts @@ -0,0 +1 @@ +export const SPOT_QUOTE_FEE_BPS = 9; diff --git a/packages/js/src/plugins/spotInstrumentModule/index.ts b/packages/js/src/plugins/spotInstrumentModule/index.ts index f43b75927..dfc197785 100644 --- a/packages/js/src/plugins/spotInstrumentModule/index.ts +++ b/packages/js/src/plugins/spotInstrumentModule/index.ts @@ -2,3 +2,6 @@ export * from './programs'; export * from './instruments'; export * from './plugin'; export * from './types'; +export * from './pdas'; +export * from './models'; +export * from './operations'; diff --git a/packages/js/src/plugins/spotInstrumentModule/instruments.ts b/packages/js/src/plugins/spotInstrumentModule/instruments.ts index 11ac793a3..4381ad8aa 100644 --- a/packages/js/src/plugins/spotInstrumentModule/instruments.ts +++ b/packages/js/src/plugins/spotInstrumentModule/instruments.ts @@ -5,14 +5,17 @@ import { publicKey } from '@convergence-rfq/beet-solana'; import { Mint } from '../tokenModule'; import { - CreateOptionInstrumentsResult, LegInstrument, QuoteInstrument, + getInstrumentProgramIndex, + CreateOptionInstrumentsResult, } from '../instrumentModule'; import { Convergence } from '../../Convergence'; import { createSerializerFromFixableBeetArgsStruct } from '../../types'; import { removeDecimals } from '../../utils/conversions'; import { LegSide, fromSolitaLegSide } from '../rfqModule/models/LegSide'; +import { Protocol } from '../protocolModule'; +import { SPOT_INSTRUMENT_PROGRAM_ID } from './types'; type InstrumentData = { mintAddress: PublicKey; @@ -32,20 +35,27 @@ export const SpotInstrumentDataSerializer = * @group Models */ export class SpotLegInstrument implements LegInstrument { + legType: 'escrow'; + constructor( readonly convergence: Convergence, readonly mintAddress: PublicKey, readonly baseAssetIndex: BaseAssetIndex, + readonly instrumentIndex: number, readonly amount: number, readonly decimals: number, readonly side: LegSide - ) {} + ) { + this.legType = 'escrow'; + } + getInstrumentIndex = () => this.instrumentIndex; getProgramId = () => this.convergence.programs().getSpotInstrument().address; + getBaseAssetIndex = () => this.baseAssetIndex; + getAssetMint = () => this.mintAddress; getSide = () => this.side; getDecimals = () => this.decimals; getAmount = () => this.amount; - getBaseAssetIndex = () => this.baseAssetIndex; async getPreparationsBeforeRfqCreation(): Promise { return []; } @@ -68,10 +78,16 @@ export class SpotLegInstrument implements LegInstrument { throw Error('Stablecoin mint cannot be used in a leg!'); } + const instrumentIndex = getInstrumentProgramIndex( + await convergence.protocol().get(), + SPOT_INSTRUMENT_PROGRAM_ID + ); + return new SpotLegInstrument( convergence, mint.address, mintInfo.mintType.baseAssetIndex, + instrumentIndex, amount, mint.decimals, side @@ -99,24 +115,23 @@ export class SpotLegInstrument implements LegInstrument { } export const spotLegInstrumentParser = { - parseFromLeg(convergence: Convergence, leg: Leg): SpotLegInstrument { - const { - side, - instrumentAmount, - instrumentData, - baseAssetIndex, - instrumentDecimals, - } = leg; + parseFromLeg( + convergence: Convergence, + leg: Leg, + instrumentIndex: number + ): SpotLegInstrument { + const { side, amount, data, baseAssetIndex, amountDecimals } = leg; const { mintAddress } = SpotLegInstrument.deserializeInstrumentData( - Buffer.from(instrumentData) + Buffer.from(data) ); return new SpotLegInstrument( convergence, mintAddress, baseAssetIndex, - removeDecimals(instrumentAmount, instrumentDecimals), - instrumentDecimals, + instrumentIndex, + removeDecimals(amount, amountDecimals), + amountDecimals, fromSolitaLegSide(side) ); }, @@ -125,26 +140,36 @@ export const spotLegInstrumentParser = { export class SpotQuoteInstrument implements QuoteInstrument { protected constructor( readonly convergence: Convergence, + readonly instrumentIndex: number, readonly mintAddress: PublicKey, readonly decimals: number ) {} + getInstrumentIndex = () => this.instrumentIndex; + getAssetMint = () => this.mintAddress; getProgramId = () => this.convergence.programs().getSpotInstrument().address; getDecimals = () => this.decimals; - static async parseFromQuote( + static parseFromQuote( convergence: Convergence, + protocol: Protocol, quote: QuoteAsset - ): Promise { - const { instrumentData, instrumentDecimals } = quote; + ): QuoteInstrument { + const { data, decimals } = quote; const { mintAddress } = SpotLegInstrument.deserializeInstrumentData( - Buffer.from(instrumentData) + Buffer.from(data) + ); + + const instrumentIndex = getInstrumentProgramIndex( + protocol, + SPOT_INSTRUMENT_PROGRAM_ID ); return new SpotQuoteInstrument( convergence, + instrumentIndex, mintAddress, - instrumentDecimals + decimals ); } @@ -164,7 +189,17 @@ export class SpotQuoteInstrument implements QuoteInstrument { throw Error('Quote only supports stablecoin mints!'); } - return new SpotQuoteInstrument(convergence, mint.address, mint.decimals); + const instrumentIndex = getInstrumentProgramIndex( + await convergence.protocol().get(), + SPOT_INSTRUMENT_PROGRAM_ID + ); + + return new SpotQuoteInstrument( + convergence, + instrumentIndex, + mint.address, + mint.decimals + ); } static deserializeInstrumentData(buffer: Buffer): InstrumentData { diff --git a/packages/js/src/plugins/spotInstrumentModule/models/Config.ts b/packages/js/src/plugins/spotInstrumentModule/models/Config.ts new file mode 100644 index 000000000..04a1c0201 --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/models/Config.ts @@ -0,0 +1,19 @@ +import { PublicKey } from '@solana/web3.js'; +import { removeDecimals } from '../../../utils'; +import { SpotInstrumentConfigAccount } from '../accounts'; +import { SPOT_QUOTE_FEE_BPS } from '../constants'; + +export type SpotInstrumentConfig = { + readonly model: 'spotInstrumentConfig'; + readonly address: PublicKey; + readonly feeBps: number; +}; + +/** @group Model Helpers */ +export const toSpotInstrumentConfig = ( + account: SpotInstrumentConfigAccount +): SpotInstrumentConfig => ({ + model: 'spotInstrumentConfig', + address: account.publicKey, + feeBps: removeDecimals(account.data.feeBps, SPOT_QUOTE_FEE_BPS), +}); diff --git a/packages/js/src/plugins/spotInstrumentModule/models/index.ts b/packages/js/src/plugins/spotInstrumentModule/models/index.ts new file mode 100644 index 000000000..bd37f302d --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/models/index.ts @@ -0,0 +1 @@ +export * from './Config'; diff --git a/packages/js/src/plugins/spotInstrumentModule/operations/fetchConfig.ts b/packages/js/src/plugins/spotInstrumentModule/operations/fetchConfig.ts new file mode 100644 index 000000000..1935521af --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/operations/fetchConfig.ts @@ -0,0 +1,57 @@ +import { + Operation, + OperationHandler, + OperationScope, + useOperation, +} from '../../../types'; +import { Convergence } from '../../../Convergence'; +import { SpotInstrumentConfig, toSpotInstrumentConfig } from '../models'; +import { toSpotInstrumentConfigAccount } from '../accounts'; + +const Key = 'FetchSpotInstrumentConfig' as const; + +export const fetchSpotInstrumentConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type FetchSpotInstrumentConfigOperation = Operation< + typeof Key, + FetchSpotInstrumentConfigInput, + FetchSpotInstrumentConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type FetchSpotInstrumentConfigInput = {} | undefined; + +/** + * @group Operations + * @category Outputs + */ +export type FetchSpotInstrumentConfigOutput = SpotInstrumentConfig; + +/** + * @group Operations + * @category Handlers + */ +export const fetchSpotInstrumentConfigOperationHandler: OperationHandler = + { + handle: async ( + _operation: FetchSpotInstrumentConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const { commitment } = scope; + + const configAddress = cvg.spotInstrument().pdas().config(); + const account = await cvg.rpc().getAccount(configAddress, commitment); + const configAccount = toSpotInstrumentConfigAccount(account); + + return toSpotInstrumentConfig(configAccount); + }, + }; diff --git a/packages/js/src/plugins/spotInstrumentModule/operations/index.ts b/packages/js/src/plugins/spotInstrumentModule/operations/index.ts new file mode 100644 index 000000000..8197eae6e --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/operations/index.ts @@ -0,0 +1,3 @@ +export * from './initializeConfig'; +export * from './modifyConfig'; +export * from './fetchConfig'; diff --git a/packages/js/src/plugins/spotInstrumentModule/operations/initializeConfig.ts b/packages/js/src/plugins/spotInstrumentModule/operations/initializeConfig.ts new file mode 100644 index 000000000..b8d16d828 --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/operations/initializeConfig.ts @@ -0,0 +1,108 @@ +import { createInitializeConfigInstruction } from '@convergence-rfq/spot-instrument'; +import { SPOT_QUOTE_FEE_BPS } from '../constants'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + makeConfirmOptionsFinalizedOnMainnet, + useOperation, +} from '@/types'; +import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { + TransactionBuilder, + TransactionBuilderOptions, + addDecimals, +} from '@/utils'; + +const Key = 'InitializeSpotInstrumentConfig' as const; + +export const initializeSpotInstrumentConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type InitializeSpotInstrumentConfigOperation = Operation< + typeof Key, + InitializeSpotInstrumentConfigInput, + InitializeSpotInstrumentConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type InitializeSpotInstrumentConfigInput = { + feeBps: number; +}; + +/** + * @group Operations + * @category Outputs + */ +export type InitializeSpotInstrumentConfigOutput = + SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const initializeSpotInstrumentConfigOperationHandler: OperationHandler = + { + handle: async ( + operation: InitializeSpotInstrumentConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const builder = await initializeSpotInstrumentConfigBuilder( + cvg, + operation.input, + scope + ); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + cvg, + scope.confirmOptions + ); + const output = await builder.sendAndConfirm(cvg, confirmOptions); + scope.throwIfCanceled(); + return output.response; + }, + }; + +export const initializeSpotInstrumentConfigBuilder = async ( + cvg: Convergence, + params: InitializeSpotInstrumentConfigInput, + options: TransactionBuilderOptions = {} +): Promise> => { + const { feeBps } = params; + const { programs, payer = cvg.rpc().getDefaultFeePayer() } = options; + + const spotInstrumentProgram = cvg.programs().getSpotInstrument(); + const systemProgram = cvg.programs().getSystem(programs); + + const protocol = cvg.protocol().pdas().protocol(); + const config = cvg.spotInstrument().pdas().config(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction: createInitializeConfigInstruction( + { + protocol, + authority: cvg.identity().publicKey, + config, + systemProgram: systemProgram.address, + }, + { + feeBps: addDecimals(feeBps, SPOT_QUOTE_FEE_BPS), + }, + spotInstrumentProgram.address + ), + signers: [payer], + key: 'initializeSpotInstrumentConfig', + }); +}; diff --git a/packages/js/src/plugins/spotInstrumentModule/operations/modifyConfig.ts b/packages/js/src/plugins/spotInstrumentModule/operations/modifyConfig.ts new file mode 100644 index 000000000..1a2c4f2c0 --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/operations/modifyConfig.ts @@ -0,0 +1,106 @@ +import { createModifyConfigInstruction } from '@convergence-rfq/spot-instrument'; +import { SPOT_QUOTE_FEE_BPS } from '../constants'; +import { Convergence } from '@/Convergence'; +import { + Operation, + OperationHandler, + OperationScope, + makeConfirmOptionsFinalizedOnMainnet, + useOperation, +} from '@/types'; +import { SendAndConfirmTransactionResponse } from '@/plugins'; +import { + TransactionBuilder, + TransactionBuilderOptions, + addDecimals, +} from '@/utils'; + +const Key = 'ModifySpotInstrumentConfig' as const; + +export const modifySpotInstrumentConfigOperation = + useOperation(Key); + +/** + * @group Operations + * @category Types + */ +export type ModifySpotInstrumentConfigOperation = Operation< + typeof Key, + ModifySpotInstrumentConfigInput, + ModifySpotInstrumentConfigOutput +>; + +/** + * @group Operations + * @category Inputs + */ +export type ModifySpotInstrumentConfigInput = { + feeBps: number; +}; + +/** + * @group Operations + * @category Outputs + */ +export type ModifySpotInstrumentConfigOutput = + SendAndConfirmTransactionResponse; + +/** + * @group Operations + * @category Handlers + */ +export const modifySpotInstrumentConfigOperationHandler: OperationHandler = + { + handle: async ( + operation: ModifySpotInstrumentConfigOperation, + cvg: Convergence, + scope: OperationScope + ): Promise => { + const builder = await modifySpotInstrumentBuilder( + cvg, + operation.input, + scope + ); + scope.throwIfCanceled(); + + const confirmOptions = makeConfirmOptionsFinalizedOnMainnet( + cvg, + scope.confirmOptions + ); + const output = await builder.sendAndConfirm(cvg, confirmOptions); + scope.throwIfCanceled(); + return output.response; + }, + }; + +export const modifySpotInstrumentBuilder = async ( + cvg: Convergence, + params: ModifySpotInstrumentConfigInput, + options: TransactionBuilderOptions = {} +): Promise> => { + const { feeBps } = params; + const { payer = cvg.rpc().getDefaultFeePayer() } = options; + + const spotProgram = cvg.programs().getSpotInstrument(); + + const protocol = cvg.protocol().pdas().protocol(); + const config = cvg.spotInstrument().pdas().config(); + + return TransactionBuilder.make<{}>() + .setFeePayer(payer) + .add({ + instruction: createModifyConfigInstruction( + { + protocol, + authority: cvg.identity().publicKey, + config, + }, + { + feeBps: addDecimals(feeBps, SPOT_QUOTE_FEE_BPS), + }, + spotProgram.address + ), + signers: [payer], + key: 'ModifySpotInstrumentConfig', + }); +}; diff --git a/packages/js/src/plugins/spotInstrumentModule/pdas.ts b/packages/js/src/plugins/spotInstrumentModule/pdas.ts new file mode 100644 index 000000000..d1e5e9a5d --- /dev/null +++ b/packages/js/src/plugins/spotInstrumentModule/pdas.ts @@ -0,0 +1,15 @@ +import { Convergence } from '@/Convergence'; +import { Pda, Program } from '@/types'; + +export class SpotInstrumentPdasClient { + constructor(protected readonly cvg: Convergence) {} + + config(): Pda { + const programId = this.programId(); + return Pda.find(programId, [Buffer.from('config', 'utf8')]); + } + + private programId(programs?: Program[]) { + return this.cvg.programs().getSpotInstrument(programs).address; + } +} diff --git a/packages/js/src/plugins/spotInstrumentModule/plugin.ts b/packages/js/src/plugins/spotInstrumentModule/plugin.ts index 966e86dae..64e5a3846 100644 --- a/packages/js/src/plugins/spotInstrumentModule/plugin.ts +++ b/packages/js/src/plugins/spotInstrumentModule/plugin.ts @@ -1,6 +1,15 @@ import { PROGRAM_ID } from '@convergence-rfq/spot-instrument'; import { ProgramClient } from '../programModule'; import { spotLegInstrumentParser } from './instruments'; +import { SpotInstrumentClient } from './client'; +import { + fetchSpotInstrumentConfigOperation, + fetchSpotInstrumentConfigOperationHandler, + initializeSpotInstrumentConfigOperation, + initializeSpotInstrumentConfigOperationHandler, + modifySpotInstrumentConfigOperation, + modifySpotInstrumentConfigOperationHandler, +} from './operations'; import { ConvergencePlugin, Program } from '@/types'; import type { Convergence } from '@/Convergence'; @@ -20,6 +29,24 @@ export const spotInstrumentModule = (): ConvergencePlugin => ({ return this.get(spotInstrumentProgram.name, programs); }; + convergence.spotInstrument = function () { + return new SpotInstrumentClient(this); + }; + + const op = convergence.operations(); + op.register( + fetchSpotInstrumentConfigOperation, + fetchSpotInstrumentConfigOperationHandler + ); + op.register( + initializeSpotInstrumentConfigOperation, + initializeSpotInstrumentConfigOperationHandler + ); + op.register( + modifySpotInstrumentConfigOperation, + modifySpotInstrumentConfigOperationHandler + ); + convergence.addLegInstrument( spotInstrumentProgram.address, spotLegInstrumentParser @@ -27,6 +54,12 @@ export const spotInstrumentModule = (): ConvergencePlugin => ({ }, }); +declare module '../../Convergence' { + interface Convergence { + spotInstrument(): SpotInstrumentClient; + } +} + declare module '../programModule/ProgramClient' { interface ProgramClient { getSpotInstrument(programs?: Program[]): Program; diff --git a/packages/js/src/plugins/spotInstrumentModule/types.ts b/packages/js/src/plugins/spotInstrumentModule/types.ts index d4665915a..156c3f736 100644 --- a/packages/js/src/plugins/spotInstrumentModule/types.ts +++ b/packages/js/src/plugins/spotInstrumentModule/types.ts @@ -1 +1 @@ -export { PROGRAM_ADDRESS as SPOT_INSTRUMENT_PROGRAM_ADDRESS } from '@convergence-rfq/spot-instrument'; \ No newline at end of file +export { PROGRAM_ID as SPOT_INSTRUMENT_PROGRAM_ID } from '@convergence-rfq/spot-instrument'; diff --git a/packages/js/src/utils/TransactionBuilder.ts b/packages/js/src/utils/TransactionBuilder.ts index d83064e0a..8994f7ef5 100644 --- a/packages/js/src/utils/TransactionBuilder.ts +++ b/packages/js/src/utils/TransactionBuilder.ts @@ -212,6 +212,57 @@ export class TransactionBuilder { return transaction; } + protected cloneWithoutRecords(): TransactionBuilder { + const result = TransactionBuilder.make(this.transactionOptions); + if (this.feePayer !== undefined) { + result.setFeePayer(this.feePayer); + } + + result.setContext(this.context); + + return result; + } + + divideToMultipleBuildersThatFit(): TransactionBuilder[] { + if (this.checkTransactionFits()) { + return [this]; + } + + if (this.records.length === 0) { + return []; + } + + const builders: TransactionBuilder[] = []; + let unprocessedRecords = [...this.records]; + + while (unprocessedRecords.length > 0) { + let builderAdded = false; + for ( + let recordsToTake = unprocessedRecords.length; + recordsToTake > 0; + recordsToTake-- + ) { + const records = unprocessedRecords.slice(0, recordsToTake); + const builder = this.cloneWithoutRecords().append(...records); + + if (builder.checkTransactionFits()) { + builders.push(builder); + unprocessedRecords = unprocessedRecords.slice(recordsToTake); + builderAdded = true; + break; + } + } + + if (!builderAdded) { + throw new Error( + `Instruction ${unprocessedRecords[0].key} is too big to fit into the transaction` + ); + } + } + + return builders; + } + async sendAndConfirm( convergence: Convergence, confirmOptions?: ConfirmOptions diff --git a/packages/js/src/utils/Wallets.ts b/packages/js/src/utils/Wallets.ts index 8d47cc6ff..d6e19c85c 100644 --- a/packages/js/src/utils/Wallets.ts +++ b/packages/js/src/utils/Wallets.ts @@ -1,4 +1,9 @@ -import { Keypair, PublicKey, Transaction } from '@solana/web3.js'; +import { + Keypair, + PublicKey, + Transaction, + VersionedTransaction, +} from '@solana/web3.js'; import { Convergence } from '..'; interface Wallet { @@ -18,12 +23,26 @@ export class CvgWallet implements Wallet { this.publicKey = convergence.identity().publicKey; } - signTransaction = (tx: Transaction): Promise => { - return this.convergence.identity().signTransaction(tx); + signTransaction = ( + tx: T + ): Promise => { + if (tx instanceof VersionedTransaction) { + throw new Error('Versioned transactions are not supported yet'); + } + + return this.convergence.identity().signTransaction(tx) as Promise; }; - signAllTransactions = (txs: Transaction[]): Promise => { - return this.convergence.identity().signAllTransactions(txs); + signAllTransactions = ( + txs: T[] + ): Promise => { + if (txs.find((tx) => tx instanceof VersionedTransaction) !== undefined) { + throw new Error('Versioned transactions are not supported yet'); + } + + return this.convergence + .identity() + .signAllTransactions(txs as Transaction[]) as Promise; }; } diff --git a/packages/js/src/utils/cache.ts b/packages/js/src/utils/cache.ts index 4f586e23f..eb1accdf2 100644 --- a/packages/js/src/utils/cache.ts +++ b/packages/js/src/utils/cache.ts @@ -3,10 +3,15 @@ interface CahcedValue { time: number; } +export type CvgCache = { + get: (...u: U) => Promise; + clear: () => void; +}; + export const useCache = ( valueGetter: (...u: U) => Promise, stalenessSeconds = 300 -) => { +): CvgCache => { const stalenessMs = stalenessSeconds * 1_000; let cache: CahcedValue | null = null; let operation: Promise | undefined; @@ -43,4 +48,4 @@ export const useCache = ( operation = undefined; }, }; -}; \ No newline at end of file +}; diff --git a/packages/js/src/utils/classes.ts b/packages/js/src/utils/classes.ts index 23a42ce0e..f775a69eb 100644 --- a/packages/js/src/utils/classes.ts +++ b/packages/js/src/utils/classes.ts @@ -32,6 +32,7 @@ export class InstructionUniquenessTracker { ) ); }; + checkedAdd( ix: TransactionInstruction | TransactionBuilder, ixType: IxType @@ -57,6 +58,19 @@ export class InstructionUniquenessTracker { throw new Error('Invalid Instruction type'); } } + + static dedup(builders: TransactionBuilder[]): TransactionBuilder[] { + const tracker = new InstructionUniquenessTracker([]); + const result = []; + for (const builder of builders) { + const isUnique = tracker.checkedAdd(builder, 'TransactionBuilder'); + if (isUnique) { + result.push(builder); + } + } + + return result; + } } export class RfqTimers { diff --git a/packages/js/tests/helpers.ts b/packages/js/tests/helpers.ts index 22d2a95b5..a5aa40af2 100644 --- a/packages/js/tests/helpers.ts +++ b/packages/js/tests/helpers.ts @@ -20,7 +20,7 @@ import { SpotLegInstrument, Mint, } from '../src'; -import { getUserKp, RPC_ENDPOINT } from '../../validator'; +import { getUserKp, HXRO_RISK_ENGINE, RPC_ENDPOINT } from '../../validator'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from './constants'; const DEFAULT_COMMITMENT = 'confirmed'; const DEFAULT_SKIP_PREFLIGHT = true; @@ -74,6 +74,14 @@ export const sleep = (seconds: number) => { return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); }; +export async function runInParallelWithWait( + promiseGetter: () => Promise, + waitInSeconds: number +): Promise { + const [result] = await Promise.all([promiseGetter(), sleep(waitInSeconds)]); + return result; +} + export const fetchTokenAmount = async ( cvg: Convergence, mintAddress: PublicKey @@ -467,7 +475,6 @@ export const respondToRfq = async ( throw new Error('Must provide bid and/or ask'); } return await cvg.rfqs().respond({ - maker: cvg.identity(), rfq: rfq.address, bid: bid ? { price: bid, legsMultiplier } : undefined, ask: ask ? { price: ask, legsMultiplier } : undefined, @@ -494,10 +501,7 @@ export const settleRfq = async ( response: Response ) => { return await cvg.rfqs().settle({ - rfq: rfq.address, response: response.address, - maker: response.maker, - taker: rfq.taker, }); }; @@ -709,3 +713,19 @@ export const expectError = async (promise: Promise, errorText: string) => { } } }; + +let hxroOperatorTRGInitialized = false; + +export const ensureHxroOperatorTRGInitialized = async ( + cvgAuthority: Convergence +) => { + if (hxroOperatorTRGInitialized) { + return; + } + + await cvgAuthority.hxro().initializeOperatorTraderRiskGroup({ + hxroRiskEngineAddress: new PublicKey(HXRO_RISK_ENGINE), + }); + + hxroOperatorTRGInitialized = true; +}; diff --git a/packages/js/tests/integration/hxro.spec.ts b/packages/js/tests/integration/hxro.spec.ts new file mode 100644 index 000000000..218ea2fdc --- /dev/null +++ b/packages/js/tests/integration/hxro.spec.ts @@ -0,0 +1,333 @@ +import { + HxroAdditionalRespondData, + HxroPrintTrade, + PrintTrade, +} from '../../src'; +import { + createUserCvg, + ensureHxroOperatorTRGInitialized, + runInParallelWithWait, + sleep, +} from '../helpers'; +import { CTX, DAO_PK, MAKER_PK } from '../constants'; + +describe('integration.hxro', () => { + const cvgTaker = createUserCvg('taker'); + const cvgMaker = createUserCvg('maker'); + const cvgAuthority = createUserCvg('dao'); + + let commonPrintTrade: PrintTrade; + + before(async () => { + await ensureHxroOperatorTRGInitialized(cvgAuthority); + const products = await cvgTaker.hxro().fetchProducts(); + commonPrintTrade = new HxroPrintTrade(cvgTaker, CTX.hxroTakerTrg, [ + { amount: 1, side: 'long', productInfo: products[0] }, + ]); + }); + + it('create, cancel and clean up', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 1000, + settlingWindow: 5000, + }); + await cvgTaker.rfqs().cancelRfq({ rfq: rfq.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('create, wait for expire and clean up', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 1, + settlingWindow: 5000, + }); + await sleep(1.5); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('create, respond, wait for expire and clean up', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 2, + settlingWindow: 5000, + }); + const { rfqResponse } = await runInParallelWithWait( + () => + cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }), + 2.5 + ); + + await cvgMaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('settle and clean up', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 1000, + settlingWindow: 5000, + }); + + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 123, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + + await cvgTaker.rfqs().settle({ + response: rfqResponse.address, + }); + await cvgTaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cancelRfq({ rfq: rfq.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('settle after settling window ends and clean up', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 3, + settlingWindow: 1, + }); + const rfqResponse = await runInParallelWithWait(async () => { + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + return rfqResponse; + }, 4.5); + + await cvgTaker.rfqs().settle({ + response: rfqResponse.address, + }); + await cvgTaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('confirm, but taker defaults', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 3, + settlingWindow: 1, + }); + + const rfqResponse = await runInParallelWithWait(async () => { + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + + return rfqResponse; + }, 4.5); + + await cvgMaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'maker', + }); + + await cvgMaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('confirm, but maker defaults', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 3, + settlingWindow: 1, + }); + + const rfqResponse = await runInParallelWithWait(async () => { + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + + return rfqResponse; + }, 4.5); + + await cvgTaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'taker', + }); + + await cvgMaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('confirm, but both default', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 3, + settlingWindow: 1, + }); + + const rfqResponse = await runInParallelWithWait(async () => { + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100, legsMultiplier: 1 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + return rfqResponse; + }, 4.5); + + await cvgMaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + await cvgTaker.rfqs().cleanUpRfq({ rfq: rfq.address }); + }); + + it('confirm, but taker unlocks collateral and defaults on settlement', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'fixed-base', amount: 100 }, + activeWindow: 3600, + settlingWindow: 3600, + }); + + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgTaker.hxro().unlockCollateralByRecord({ + lockRecord: cvgTaker + .hxro() + .pdas() + .lockedCollateralRecord( + cvgTaker.identity().publicKey, + rfqResponse.address + ), + action: 'unlock', + }); + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgMaker.rfqs().settle({ + response: rfqResponse.address, + }); + + await cvgMaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'taker', + }); + await cvgMaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'maker', + }); + + await cvgMaker.rfqs().cleanUpResponse({ response: rfqResponse.address }); + }); + + it('Create a future rfq with counterparties', async () => { + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: commonPrintTrade, + orderType: 'buy', + fixedSize: { type: 'fixed-base', amount: 100 }, + activeWindow: 3600, + settlingWindow: 3600, + counterParties: [MAKER_PK, DAO_PK], + }); + + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + }); +}); diff --git a/packages/js/tests/integration/psyoptionsEuropean.spec.ts b/packages/js/tests/integration/psyoptionsEuropean.spec.ts index fe0d1caa0..e42d96778 100644 --- a/packages/js/tests/integration/psyoptionsEuropean.spec.ts +++ b/packages/js/tests/integration/psyoptionsEuropean.spec.ts @@ -14,7 +14,7 @@ import { } from '../helpers'; import { BASE_MINT_BTC_PK, QUOTE_MINT_PK } from '../constants'; import { CvgWallet, PublicKey } from '../../src'; -import { IDL as PseudoPythIdl } from '../../../validator/fixtures/programs/pseudo_pyth_idl'; +import { IDL as PseudoPythIdl } from '../../../validator/dependencies/pseudo_pyth_idl'; describe('integration.psyoptionsEuropean', () => { const takerCvg = createUserCvg('taker'); diff --git a/packages/js/tests/integration/spot.spec.ts b/packages/js/tests/integration/spot.spec.ts index abb2fec88..f640db3e4 100644 --- a/packages/js/tests/integration/spot.spec.ts +++ b/packages/js/tests/integration/spot.spec.ts @@ -38,6 +38,7 @@ describe('integration.spot', () => { it('sell', async () => { const baseAmount = 1.536_421; const quoteAmount = 22_000.86; + const feeAmount = quoteAmount * 0.01; // 1% is specified in fixtures const { rfq } = await createRfq(takerCvg, baseAmount, 'sell'); expect(rfq).toHaveProperty('address'); @@ -74,7 +75,9 @@ describe('integration.spot', () => { ]); // TODO: This does not seem right in terms of handling precision - expect(takerQuoteAfter).toBeCloseTo(takerQuoteBefore + quoteAmount); + expect(takerQuoteAfter).toBeCloseTo( + takerQuoteBefore + quoteAmount - feeAmount + ); expect(takerBtcAfter).toBeCloseTo(takerBtcBefore - baseAmount); }); diff --git a/packages/js/tests/unit/hxro.spec.ts b/packages/js/tests/unit/hxro.spec.ts new file mode 100644 index 000000000..810f26dae --- /dev/null +++ b/packages/js/tests/unit/hxro.spec.ts @@ -0,0 +1,214 @@ +import { expect } from 'expect'; + +import { Keypair } from '@solana/web3.js'; +import { createUserCvg, ensureHxroOperatorTRGInitialized } from '../helpers'; +import { + HxroPrintTrade, + HxroLeg, + PublicKey, + HxroAdditionalRespondData, +} from '../../src'; +import { CTX } from '../constants'; + +describe('unit.hxro', () => { + const cvgTaker = createUserCvg('taker'); + const cvgMaker = createUserCvg('maker'); + const cvgAuthority = createUserCvg('dao'); + + before(async () => { + await ensureHxroOperatorTRGInitialized(cvgAuthority); + }); + + it('get hxro config', async () => { + const result = await cvgTaker.hxro().fetchConfig(); + expect(result).toEqual({ + model: 'hxroPrintTradeProviderConfig', + address: cvgTaker.hxro().pdas().config(), + validMpg: new PublicKey('GCXr6LDZurWK8Hkm18gZzJ7jUgvrYEVFFeWUR346fd42'), + }); + }); + + it('get hxro products', async () => { + const results = await cvgTaker.hxro().fetchProducts(); + + expect(results).toEqual([ + { + productIndex: 0, + productAddress: new PublicKey( + '3fw72yL2pG7cKmPs4TYJa6C9496NyypFpj5UQVLe515j' + ), + baseAssetIndex: 1, + instrumentType: 'perp-future', + productName: 'product 0', + }, + { + productIndex: 1, + productAddress: new PublicKey( + '8qBD1ZewtfoxNAy3E45f5fRtwQUhLku55cVVxT5cMPef' + ), + baseAssetIndex: 1, + instrumentType: 'perp-future', + productName: 'product 1', + }, + ]); + }); + + it('can modify hxro config', async () => { + const randomKey = new Keypair().publicKey; + const { validMpg: oldMpg } = await cvgAuthority.hxro().fetchConfig(); + await cvgAuthority.hxro().modifyConfig({ validMpg: randomKey }); + const { validMpg } = await cvgAuthority.hxro().fetchConfig(); + expect(validMpg).toEqual(randomKey); + + // set back + await cvgAuthority.hxro().modifyConfig({ validMpg: oldMpg }); + }); + + it('can overwrite print trade with whole product data', async () => { + const products = await cvgTaker.hxro().fetchProducts(); + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: new HxroPrintTrade(cvgTaker, CTX.hxroTakerTrg, [ + { amount: 1, side: 'long', productInfo: products[0] }, + ]), + orderType: 'buy', + fixedSize: { type: 'open' }, + activeWindow: 1000, + settlingWindow: 5000, + }); + + expect( + (rfq.legs[0] as HxroLeg).legInfo.productInfo.productAddress + ).toBeUndefined(); + (rfq.printTrade as HxroPrintTrade).overwriteWithFullHxroProductData( + products + ); + expect( + (rfq.legs[0] as HxroLeg).legInfo.productInfo.productAddress + ).toBeDefined(); + }); + + it('revert preparation by the same cvg party automatically removes a lock', async () => { + const products = await cvgTaker.hxro().fetchProducts(); + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: new HxroPrintTrade(cvgTaker, CTX.hxroTakerTrg, [ + { amount: 1, side: 'long', productInfo: products[0] }, + ]), + orderType: 'buy', + fixedSize: { type: 'fixed-base', amount: 100 }, + activeWindow: 3600, + settlingWindow: 3600, + }); + + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgTaker.hxro().unlockCollateralByRecord({ + lockRecord: cvgTaker + .hxro() + .pdas() + .lockedCollateralRecord( + cvgTaker.identity().publicKey, + rfqResponse.address + ), + action: 'unlock', + }); + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgMaker.rfqs().settle({ + response: rfqResponse.address, + }); + + await cvgMaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'maker', + }); + + const lockAddress = cvgMaker + .hxro() + .pdas() + .lockedCollateralRecord( + cvgMaker.identity().publicKey, + rfqResponse.address + ); + const lockData = await cvgMaker.connection.getAccountInfo(lockAddress); + expect(lockData).toBeNull(); + }); + + it('can fetch an unused lock', async () => { + const products = await cvgTaker.hxro().fetchProducts(); + const { rfq } = await cvgTaker.rfqs().createPrintTrade({ + printTrade: new HxroPrintTrade(cvgTaker, CTX.hxroTakerTrg, [ + { amount: 1, side: 'long', productInfo: products[0] }, + ]), + orderType: 'buy', + fixedSize: { type: 'fixed-base', amount: 100 }, + activeWindow: 3600, + settlingWindow: 3600, + }); + + const { rfqResponse } = await cvgMaker.rfqs().respond({ + rfq: rfq.address, + ask: { price: 100 }, + additionalData: new HxroAdditionalRespondData(CTX.hxroMakerTrg), + }); + await cvgTaker.rfqs().confirmResponse({ + response: rfqResponse.address, + rfq: rfq.address, + side: 'ask', + }); + + await cvgTaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgTaker.hxro().unlockCollateralByRecord({ + lockRecord: cvgTaker + .hxro() + .pdas() + .lockedCollateralRecord( + cvgTaker.identity().publicKey, + rfqResponse.address + ), + action: 'unlock', + }); + await cvgMaker.rfqs().preparePrintTradeSettlement({ + rfq: rfq.address, + response: rfqResponse.address, + }); + await cvgMaker.rfqs().settle({ + response: rfqResponse.address, + }); + + await cvgMaker.rfqs().revertSettlementPreparation({ + response: rfqResponse.address, + side: 'taker', + }); + + const lockKeys = ( + await cvgTaker.hxro().fetchUnusedCollateralLockRecords() + ).map((lock) => lock.publicKey); + const expectedKey = cvgTaker + .hxro() + .pdas() + .lockedCollateralRecord( + cvgTaker.identity().publicKey, + rfqResponse.address + ); + + expect(lockKeys.find((key) => key.equals(expectedKey))).toBeTruthy(); + }); +}); diff --git a/packages/js/tests/unit/protocol.spec.ts b/packages/js/tests/unit/protocol.spec.ts index d0c8e7fd7..0196d65e6 100644 --- a/packages/js/tests/unit/protocol.spec.ts +++ b/packages/js/tests/unit/protocol.spec.ts @@ -4,6 +4,8 @@ import { protocolCache, baseAssetsCache, registeredMintsCache, + toPriceOracle, + BaseAsset, } from '../../src'; import { createUserCvg, generateTicker } from '../helpers'; import { @@ -74,7 +76,7 @@ describe('unit.protocol', () => { canBeUsedAsQuote: true, validateDataAccountAmount: 1, prepareToSettleAccountAmount: 7, - settleAccountAmount: 3, + settleAccountAmount: 5, revertPreparationAccountAmount: 3, cleanUpAccountAmount: 4, }); @@ -111,6 +113,16 @@ describe('unit.protocol', () => { expect(response).toHaveProperty('signature'); }); + it('add print trade provider [hxro]', async () => { + const { response } = await cvg.protocol().addPrintTradeProvider({ + printTradeProviderProgram: cvg.programs().getHxroPrintTradeProvider() + .address, + settlementCanExpire: false, + validateResponseAccountAmount: 2, + }); + expect(response).toHaveProperty('signature'); + }); + it('add base asset [switchboard oracle]', async () => { const baseAssets = await cvg.protocol().getBaseAssets(); const { response } = await cvg.protocol().addBaseAsset({ @@ -166,7 +178,20 @@ describe('unit.protocol', () => { const baseAsset = await cvg .protocol() .findBaseAssetByAddress({ address: baseAssetPda }); - expect(baseAsset.priceOracle.price).toEqual(price); + expect(toPriceOracle(baseAsset).price).toEqual(price); + }); + + it('change base asset parameters', async () => { + const { response } = await cvg.protocol().changeBaseAssetParameters({ + index: 0, + enabled: true, + inPlacePrice: 42, + }); + expect(response).toHaveProperty('signature'); + + const baseAssets: BaseAsset[] = await cvg.protocol().getBaseAssets(); + const baseAsset = baseAssets.find((x) => x.index === 0); + expect(baseAsset?.inPlacePrice).toBe(42); }); it('register mint', async () => { diff --git a/packages/js/tests/unit/response.spec.ts b/packages/js/tests/unit/response.spec.ts index adbda7e88..dc991132c 100644 --- a/packages/js/tests/unit/response.spec.ts +++ b/packages/js/tests/unit/response.spec.ts @@ -168,10 +168,6 @@ describe('unit.response', () => { address: rfq2.address, }); - await makerCvg.rfqs().unlockResponsesCollateral({ - responses: responsesBefore.map((r) => r.address), - }); - const responsesAfter = await makerCvg.rfqs().findResponsesByRfq({ address: rfq2.address, }); @@ -184,7 +180,6 @@ describe('unit.response', () => { }); await makerCvg.rfqs().cleanUpResponse({ response: responses[0].address, - maker: makerCvg.identity().publicKey, }); }); @@ -227,7 +222,7 @@ describe('unit.response', () => { }); it('Cannot confirm Response if response is expired', async () => { - const rfq = await createRfq(takerCvg, amount0, 'buy', 10); + const rfq = await createRfq(takerCvg, amount0, 'buy', [], 10); const res = await respondToRfq( makerCvg, @@ -237,7 +232,7 @@ describe('unit.response', () => { convertTimestampToSeconds(Date.now()) + 2 ); - await sleep(2); + await sleep(3); await expectError( takerCvg.rfqs().confirmResponse({ @@ -248,13 +243,8 @@ describe('unit.response', () => { 'Response is expired' ); - await makerCvg.rfqs().unlockResponseCollateral({ - response: res.rfqResponse.address, - }); - await makerCvg.rfqs().cleanUpResponse({ response: res.rfqResponse.address, - maker: makerCvg.identity().publicKey, }); }); }); diff --git a/packages/js/tests/unit/responseStateAndAction.spec.ts b/packages/js/tests/unit/responseStateAndAction.spec.ts index a91c00497..5c48d4f7d 100644 --- a/packages/js/tests/unit/responseStateAndAction.spec.ts +++ b/packages/js/tests/unit/responseStateAndAction.spec.ts @@ -72,22 +72,6 @@ describe('unit.responseStateAndAction', () => { }).responseState ).toBe('Cancelled'); - //Unlock Response Collateral for maker - refreshedResponse = await makerCvg.rfqs().findResponseByAddress({ - address: rfqResponse.address, - }); - expect( - takerCvg.rfqs().getResponseStateAndAction({ - response: refreshedResponse, - rfq, - caller: 'maker', - responseSide: 'bid', - }).responseAction - ).toBe('UnlockCollateral'); - await makerCvg.rfqs().unlockResponseCollateral({ - response: refreshedResponse.address, - }); - //Cleanup for maker refreshedResponse = await makerCvg.rfqs().findResponseByAddress({ address: rfqResponse.address, @@ -103,7 +87,6 @@ describe('unit.responseStateAndAction', () => { await makerCvg.rfqs().cleanUpResponse({ response: rfqResponse.address, - maker: makerCvg.identity().publicKey, }); }); @@ -182,9 +165,6 @@ describe('unit.responseStateAndAction', () => { await takerCvg.rfqs().settle({ response: rfqResponse.address, - rfq: rfq.address, - maker: makerCvg.identity().publicKey, - taker: takerCvg.identity().publicKey, }); //Settled for maker diff --git a/packages/js/tests/unit/rfq.spec.ts b/packages/js/tests/unit/rfq.spec.ts index 9fd4b571f..d3655f5ba 100644 --- a/packages/js/tests/unit/rfq.spec.ts +++ b/packages/js/tests/unit/rfq.spec.ts @@ -72,30 +72,6 @@ describe('unit.rfq', () => { expect(responses.length).toBe(rfqs.length); }); - it('unlock', async () => { - const iterator: any = takerCvg.rfqs().findRfqs({}); - const rfqsBefore = (await getAll(iterator)).flat().filter((rfq: any) => { - return ( - takerCvg.rfqs().getRfqStateAndAction({ rfq, caller: 'taker' }) - .rfqAction === 'UnlockCollateral' - ); - }); - expect(rfqsBefore.length).toBeGreaterThan(0); - const { responses } = await takerCvg.rfqs().unlockRfqsCollateral({ - rfqs: rfqsBefore.map((rfq: any) => rfq.address), - }); - expect(responses.length).toBe(rfqsBefore.length); - const rfqsAfter = (await getAll(iterator)).flat().filter((rfq: any) => { - return ( - takerCvg.rfqs().getRfqStateAndAction({ rfq, caller: 'taker' }) - .rfqAction === 'Cleanup' - ); - }); - rfqsAfter.map((rfq: any) => { - expect(rfq.totalTakerCollateralLocked).toBe(0); - }); - }); - it('clean up', async () => { const iterator: any = takerCvg.rfqs().findRfqs({}); const rfqs = (await getAll(iterator)).flat().filter((rfq: any) => { diff --git a/packages/js/tests/unit/rfqStateAndAction.spec.ts b/packages/js/tests/unit/rfqStateAndAction.spec.ts index a65806413..872179695 100644 --- a/packages/js/tests/unit/rfqStateAndAction.spec.ts +++ b/packages/js/tests/unit/rfqStateAndAction.spec.ts @@ -61,29 +61,6 @@ describe('unit.rfqStateAndAction', () => { address: rfq.address, }); - //UnlockCollateral for taker - expect( - takerCvg.rfqs().getRfqStateAndAction({ - rfq: refreshedRfq, - caller: 'taker', - }).rfqAction - ).toBe('UnlockCollateral'); - - //null for maker - expect( - takerCvg.rfqs().getRfqStateAndAction({ - rfq: refreshedRfq, - caller: 'maker', - }).rfqAction - ).toBe(null); - - await takerCvg.rfqs().unlockRfqCollateral({ - rfq: rfq.address, - }); - refreshedRfq = await makerCvg.rfqs().findRfqByAddress({ - address: rfq.address, - }); - //Cleanup for taker expect( takerCvg.rfqs().getRfqStateAndAction({ @@ -169,34 +146,10 @@ describe('unit.rfqStateAndAction', () => { await sleep(4); - //UnlockCollateral for taker - expect( - takerCvg.rfqs().getRfqStateAndAction({ - rfq, - caller: 'taker', - }).rfqAction - ).toBe('UnlockCollateral'); - - //null for maker - expect( - takerCvg.rfqs().getRfqStateAndAction({ - rfq, - caller: 'maker', - }).rfqAction - ).toBe(null); - - await takerCvg.rfqs().unlockRfqCollateral({ - rfq: rfq.address, - }); - - const refreshedRfq = await makerCvg.rfqs().findRfqByAddress({ - address: rfq.address, - }); - //Cleanup for taker expect( takerCvg.rfqs().getRfqStateAndAction({ - rfq: refreshedRfq, + rfq, caller: 'taker', }).rfqAction ).toBe('Cleanup'); diff --git a/packages/js/tests/unit/riskEngine.spec.ts b/packages/js/tests/unit/riskEngine.spec.ts index 752627106..b3ff9f065 100644 --- a/packages/js/tests/unit/riskEngine.spec.ts +++ b/packages/js/tests/unit/riskEngine.spec.ts @@ -1,6 +1,6 @@ import { expect } from 'expect'; -import { InstrumentType, DEFAULT_RISK_CATEGORIES_INFO } from '../../src'; +import { DEFAULT_RISK_CATEGORIES_INFO } from '../../src'; import { createCFlyRfq, createRfq, @@ -35,7 +35,7 @@ describe('unit.riskEngine', () => { it('set instrument type [spot]', async () => { const { config } = await daoCvg.riskEngine().setInstrumentType({ - instrumentType: InstrumentType.Spot, + instrumentType: 'spot', instrumentProgram: daoCvg.programs().getSpotInstrument().address, }); expect(config.address).toEqual(daoCvg.riskEngine().pdas().config()); @@ -43,7 +43,7 @@ describe('unit.riskEngine', () => { it('set instrument type [american]', async () => { const { config } = await daoCvg.riskEngine().setInstrumentType({ - instrumentType: InstrumentType.Option, + instrumentType: 'option', instrumentProgram: daoCvg.programs().getPsyoptionsAmericanInstrument() .address, }); @@ -52,7 +52,7 @@ describe('unit.riskEngine', () => { it('set instrument type [european]', async () => { const { config } = await daoCvg.riskEngine().setInstrumentType({ - instrumentType: InstrumentType.Option, + instrumentType: 'option', instrumentProgram: daoCvg.programs().getPsyoptionsEuropeanInstrument() .address, }); @@ -125,7 +125,6 @@ describe('unit.riskEngine', () => { .riskEngine() .calculateCollateralForRfq({ legs: rfq.legs, - quoteAsset: rfq.quoteAsset, settlementPeriod: rfq.settlingWindow, size: rfq.size, orderType: rfq.orderType, @@ -166,7 +165,6 @@ describe('unit.riskEngine', () => { .riskEngine() .calculateCollateralForRfq({ legs: rfq.legs, - quoteAsset: rfq.quoteAsset, settlementPeriod: rfq.settlingWindow, size: rfq.size, orderType: rfq.orderType, @@ -180,7 +178,6 @@ describe('unit.riskEngine', () => { .riskEngine() .calculateCollateralForRfq({ legs: rfq.legs, - quoteAsset: rfq.quoteAsset, settlementPeriod: rfq.settlingWindow, size: rfq.size, orderType: rfq.orderType, diff --git a/packages/validator/dependencies/hxro/accounts/execution-output.json b/packages/validator/dependencies/hxro/accounts/execution-output.json new file mode 100644 index 000000000..e15cb5d7f --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/execution-output.json @@ -0,0 +1,13 @@ +{ + "pubkey": "6Prp1p7vjS6LCb8xR1oQqsbUPX9AWaHz9PBVbdzAFHT4", + "account": { + "lamports": 953520, + "data": [ + "UXUBZI2/164A", + "base64" + ], + "owner": "FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/fee-config.json b/packages/validator/dependencies/hxro/accounts/fee-config.json new file mode 100644 index 000000000..1e25ad1b1 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/fee-config.json @@ -0,0 +1,13 @@ +{ + "pubkey": "GBhshm4LFyYTv9iPocz7kmLpRhvvPNoxH9wgB57uNamm", + "account": { + "lamports": 946560, + "data": [ + "AAAAAAAAAAA=", + "base64" + ], + "owner": "5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/fee-output.json b/packages/validator/dependencies/hxro/accounts/fee-output.json new file mode 100644 index 000000000..3f52f48a7 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/fee-output.json @@ -0,0 +1,13 @@ +{ + "pubkey": "4Ucpj5hWiz8msBQVgFSUnqxQCkJWEPn5YbpwFbbhxoa6", + "account": { + "lamports": 1002240, + "data": [ + "AAAAAAAAAAAAAAAAAAAAAA==", + "base64" + ], + "owner": "5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/maker-fee-state.json b/packages/validator/dependencies/hxro/accounts/maker-fee-state.json new file mode 100644 index 000000000..8c9e633ba --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/maker-fee-state.json @@ -0,0 +1,13 @@ +{ + "pubkey": "FU68EKUppMq89TSVBELYpbsdw2FpzKwx79mPvCARmM9t", + "account": { + "lamports": 946560, + "data": [ + "/wAAAAAAAAA=", + "base64" + ], + "owner": "5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/maker-risk-state.json b/packages/validator/dependencies/hxro/accounts/maker-risk-state.json new file mode 100644 index 000000000..c0c757f63 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/maker-risk-state.json @@ -0,0 +1,13 @@ +{ + "pubkey": "EDHbf67fJZBZoKFJGPEC7b9qimnave5DiYBctVWEysYb", + "account": { + "lamports": 953520, + "data": [ + "2JJrXmhLtrEB", + "base64" + ], + "owner": "BVDTB61eHY7UnCb4ueatdaV4rctTzqfLAL6sQDeMNSHA", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/maker-trg.json b/packages/validator/dependencies/hxro/accounts/maker-trg.json new file mode 100644 index 000000000..5f057b83d --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/maker-trg.json @@ -0,0 +1,13 @@ +{ + "pubkey": "4Lrt2YtUyEB8SrtTR3Tsb1DBGU9hRU6xNuDZd9zJrKG9", + "account": { + "lamports": 93264000, + "data": [ + "eeRuOP7P9agCAAAAAAAAAOHTkilwXhTJ/6+xI4JB3v1jOjZw3u1pPBezEe5kThdfRGcv6WZ5nR0SQFCdXFvcEqmvImWuWJkw9t9ogVLKIbf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADETaqowmWTL8A5Z1IeK5Ptu1DNZflgVf5GkHavMCpfYNb0F+C6uTJDTJYXO1cBZDZgL0bYE+kia3f+g7jx3SMTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "base64" + ], + "owner": "FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/mpg.json b/packages/validator/dependencies/hxro/accounts/mpg.json new file mode 100644 index 000000000..d5d7e36b8 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/mpg.json @@ -0,0 +1,13 @@ +{ + "pubkey": "GCXr6LDZurWK8Hkm18gZzJ7jUgvrYEVFFeWUR346fd42", + "account": { + "lamports": 1002852480, + "data": [ + "Fk3/hqMpOYYBAAAAAAAAAHRlc3RfZ3JvdXAgICAgICCd2BM5IMatN7QacL9qYfDUoSp7lW4gLLShlIwVOfE7tZ3YEzkgxq03tBpwv2ph8NShKnuVbiAstKGUjBU58Tu1e2UTGuRioXUH1thtTs+0Qj7hdyxRnoHwm55RQpy8WkYAAAAAAAAAAAAAAAAAAAAAndgTOSDGrTe0GnC/amHw1KEqe5VuICy0oZSMFTnxO7UJAAAAAAAAAJvPNesTwPbNbWhQ+qcuU4AT5K71Lu3NFZMJV/M1JwtVQiGr/PKqiZhPtLpVzg5Wj7/nezL4cN+vXxMYlbugfIzhnVQdeh5XYssMXY8h3Yrj9Evl6QBAtE3LvxsHspI/EEIhFffMSGTB6K2+ouGgyra89Qfui8b0wy2U0bwiXz2pAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWAAAAAAAAAO4CAAAAAAAAyggAAAAAAAAoIwAAAAAAAAAAAAAAAAAA/wAAAAAAAAAnsJ7HAbAJhyOWng6wgS65I6Z8m5/XiXTEajroH8vLYnByb2R1Y3QgICAgICAgIDCqQV2uWEKoyM67d1nj8k6OW9/5y1qJymkTwf10rWtYKWQAAAAAAAAABAAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAP////////9/AAAAAAAAAAD/////////fwAAAAAAAAAA/////////38AAAAAAAAAAP////////9/AAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAA/////////38AAAAAAAAAABIAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAP////////9/AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAAHRZOn3t6Ppe3Z83nNpyJPS2Zlp9fpJSUnDw5DHb37hwcHJvZHVjdCAgICAgICAgMSoHL8LeWUiaYWH3g0MzPnXIUvRcvutkOVJOrJxNKdonZAAAAAAAAAAEAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAA/////////38AAAAAAAAAAP////////9/AAAAAAAAAAD/////////fwAAAAAAAAAA/////////38AAAAAAAAAAAAAAAAAAACAAAAAAAAAAAD/////////fwAAAAAAAAAAFgAAAAAAAAAAAAAAAAAAgAAAAAAAAAAA/////////38AAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+wD/AAEACAAAAAAAAAAAACe0x+xjNoToMGnEntp6lbrI+G8kQ3zXB+gDnP/oA5z/M6Y/ZkVsV2u0C1JA/H+eDE/RUCFSWkoDAAaIGPHlD8/TfgL6AAguhJ7Kqw4mwH8Lc5n8ysQ9R+yzRg3bXJGGDgIAAAAAAAAAAAAAAAAAAACd2BM5IMatN7QacL9qYfDUoSp7lW4gLLShlIwVOfE7tQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAA=", + "base64" + ], + "owner": "FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/product-0-orderbook.json b/packages/validator/dependencies/hxro/accounts/product-0-orderbook.json new file mode 100644 index 000000000..b6c467374 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/product-0-orderbook.json @@ -0,0 +1,13 @@ +{ + "pubkey": "CTc7swEKXFCD1gsnvVcQyozXK2zJ3roQr3fuU7G6uerC", + "account": { + "lamports": 2227200, + "data": [ + "AQAAAAAAAAAcqYy6A1iSjP3wy3cOv6ZrEgOTumirhDdQ4K7/QLUAOyGtE4dJIGYBPjoaCDKI2FCzA3XwKXWYVkRLO43DdPsRB192kPMPxijVOerYoBe4JKaoj7bMWca2a9cQQZgC2tH1QHjNnhjt4+PmLihbEBIAEg1w8r86g76alyQbT0UDRSAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAD8IQAAAAAAAQAAAAAAAAABAAAAAAAAAOgDAAAAAAAA", + "base64" + ], + "owner": "DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/product-0.json b/packages/validator/dependencies/hxro/accounts/product-0.json new file mode 100644 index 000000000..a439ae386 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/product-0.json @@ -0,0 +1,13 @@ +{ + "pubkey": "3fw72yL2pG7cKmPs4TYJa6C9496NyypFpj5UQVLe515j", + "account": { + "lamports": 2449920, + "data": [ + "2iV+Bk5nKRMBAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAPsAAAAAAAAAM9QAAAAAAAACAAAAAAAAAIA8dWQAAAAAgFEBAAAAAACAcAAAAAAAAO8Ni2/aLOukHaFdQJXR2jkqDS+O0MbHvA9M+sjCgLVt4dOSKXBeFMn/r7EjgkHe/WM6NnDe7Wk8F7MR7mROF1+d2BM5IMatN7QacL9qYfDUoSp7lW4gLLShlIwVOfE7tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgDx1ZAAAAAA=", + "base64" + ], + "owner": "8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/product-1-orderbook.json b/packages/validator/dependencies/hxro/accounts/product-1-orderbook.json new file mode 100644 index 000000000..37535a29a --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/product-1-orderbook.json @@ -0,0 +1,13 @@ +{ + "pubkey": "3q4UnqSY7ARzcbX8B647soB5Xji4Qr23idLQGpZGLzJa", + "account": { + "lamports": 2227200, + "data": [ + "AQAAAAAAAAAqISmMdoAJaCx8HkO5xjNJW4Dqhq7wvw7C/zMdSp1BKSvPsRm6t+ZQfVcpMdTDwQtk4Zamrgk1d/lUI78uAz8f0id22k7YqBKMg7Gi65pFk8QC3IRbMJwgHEgYEMWlql/RuFuAeWjKnshatotZZbvqvvWuZRELzUhKRmHw68odHSAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAD8IQAAAAAAAQAAAAAAAAABAAAAAAAAAOgDAAAAAAAA", + "base64" + ], + "owner": "DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/product-1.json b/packages/validator/dependencies/hxro/accounts/product-1.json new file mode 100644 index 000000000..67034e093 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/product-1.json @@ -0,0 +1,13 @@ +{ + "pubkey": "8qBD1ZewtfoxNAy3E45f5fRtwQUhLku55cVVxT5cMPef", + "account": { + "lamports": 2449920, + "data": [ + "2iV+Bk5nKRMBAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAPwAAAAAAAAA6d0BAAAAAAAEAAAAAAAAAMBJeGQAAAAAgFEBAAAAAACAcAAAAAAAAO8Ni2/aLOukHaFdQJXR2jkqDS+O0MbHvA9M+sjCgLVt4dOSKXBeFMn/r7EjgkHe/WM6NnDe7Wk8F7MR7mROF1+d2BM5IMatN7QacL9qYfDUoSp7lW4gLLShlIwVOfE7tQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEl4ZAAAAAA=", + "base64" + ], + "owner": "8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/risk-output.json b/packages/validator/dependencies/hxro/accounts/risk-output.json new file mode 100644 index 000000000..d28717e46 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/risk-output.json @@ -0,0 +1,13 @@ +{ + "pubkey": "FEaUEZkFnyTfkWm8GgYR7sbyMkoW5nYSyqECDmKfQQoo", + "account": { + "lamports": 3897600, + "data": [ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "base64" + ], + "owner": "BVDTB61eHY7UnCb4ueatdaV4rctTzqfLAL6sQDeMNSHA", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/taker-fee-state.json b/packages/validator/dependencies/hxro/accounts/taker-fee-state.json new file mode 100644 index 000000000..1f9580753 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/taker-fee-state.json @@ -0,0 +1,13 @@ +{ + "pubkey": "12fr3WXr7Mh1wGMPQe1qe5VUeexz1BRzJ6SfAhHPgC1b", + "account": { + "lamports": 946560, + "data": [ + "/wAAAAAAAAA=", + "base64" + ], + "owner": "5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/taker-risk-state.json b/packages/validator/dependencies/hxro/accounts/taker-risk-state.json new file mode 100644 index 000000000..5135e9a7f --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/taker-risk-state.json @@ -0,0 +1,13 @@ +{ + "pubkey": "78haJHMHdjdp6phofBzQwbHdNobFyYDrGRdgfAWQfwxL", + "account": { + "lamports": 953520, + "data": [ + "2JJrXmhLtrEB", + "base64" + ], + "owner": "BVDTB61eHY7UnCb4ueatdaV4rctTzqfLAL6sQDeMNSHA", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/taker-trg.json b/packages/validator/dependencies/hxro/accounts/taker-trg.json new file mode 100644 index 000000000..0641af8b3 --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/taker-trg.json @@ -0,0 +1,13 @@ +{ + "pubkey": "A3tmPza8B4rvHFiUkPHLsL7Nnv4ERK8utFfwPa1yAn18", + "account": { + "lamports": 93264000, + "data": [ + "eeRuOP7P9agCAAAAAAAAAOHTkilwXhTJ/6+xI4JB3v1jOjZw3u1pPBezEe5kThdfyxkDb26bL0vjVHOsyuI/i4PC7QTivY42lYqpvanXNlf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbHxCDdmnV3uGtewPNfLWiEg7yUEx+GkcUMsP5U8zx4QBtgO580OoEwhjDNQ76YOLkCPYvJ+HIPiRngfboEZqmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "base64" + ], + "owner": "FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/accounts/vault.json b/packages/validator/dependencies/hxro/accounts/vault.json new file mode 100644 index 000000000..f1fe0214e --- /dev/null +++ b/packages/validator/dependencies/hxro/accounts/vault.json @@ -0,0 +1,13 @@ +{ + "pubkey": "G6b2JSF5M7SySosNC4GkHHmqXczSCGUycppRiYvTQ7aK", + "account": { + "lamports": 2039280, + "data": [ + "e2UTGuRioXUH1thtTs+0Qj7hdyxRnoHwm55RQpy8WkbgTa1eL6Zbjxal5nIpE/kYcpnP9RQiZgx7paDu540f/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "base64" + ], + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/dex.json b/packages/validator/dependencies/hxro/dex.json new file mode 100644 index 000000000..e50bf8d58 --- /dev/null +++ b/packages/validator/dependencies/hxro/dex.json @@ -0,0 +1,4605 @@ +{ + "version": "0.1.0", + "name": "dex", + "constants": [ + { + "name": "NAME_LEN", + "type": "u64", + "value": "16" + }, + { + "name": "MAX_OUTRIGHTS", + "type": "u64", + "value": "128" + }, + { + "name": "MAX_PRODUCTS", + "type": "u64", + "value": "256" + }, + { + "name": "HEALTH_BUFFER_LEN", + "type": "u64", + "value": "32" + }, + { + "name": "MAX_TRADER_POSITIONS", + "type": "u64", + "value": "16" + }, + { + "name": "MAX_OPEN_ORDERS_PER_POSITION", + "type": "u64", + "value": "256" + }, + { + "name": "MAX_OPEN_ORDERS", + "type": "u64", + "value": "1024" + }, + { + "name": "ANCHOR_DISCRIMINANT_LEN", + "type": "u64", + "value": "8" + }, + { + "name": "SENTINEL", + "type": "u64", + "value": "0" + }, + { + "name": "CALLBACK_INFO_LEN", + "type": "u64", + "value": "std :: mem :: size_of :: < CallBackInfo > () as u64" + }, + { + "name": "CALLBACK_ID_LEN", + "type": "u64", + "value": "32" + }, + { + "name": "MAX_COMBOS", + "type": "u64", + "value": "128" + }, + { + "name": "MAX_LEGS", + "type": "u64", + "value": "4" + }, + { + "name": "SLOTS_1_MIN", + "type": "u64", + "value": "150" + }, + { + "name": "SLOTS_5_MIN", + "type": "u64", + "value": "750" + }, + { + "name": "SLOTS_15_MIN", + "type": "u64", + "value": "2250" + }, + { + "name": "SLOTS_60_MIN", + "type": "u64", + "value": "9000" + } + ], + "instructions": [ + { + "name": "initializeMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultMint", + "isMut": false, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "sysvarRent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeMarketProductGroupParams" + } + } + ] + }, + { + "name": "updateMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": false, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateMarketProductGroupParams" + } + } + ] + }, + { + "name": "setAddressLookupTable", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "addressLookupTable", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeMarketProduct", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeMarketProductParams" + } + } + ] + }, + { + "name": "changeOrderbook", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "oldOrderbook", + "isMut": false, + "isSigner": false + }, + { + "name": "oldEventQueue", + "isMut": false, + "isSigner": false + }, + { + "name": "oldBids", + "isMut": false, + "isSigner": false + }, + { + "name": "oldAsks", + "isMut": false, + "isSigner": false + }, + { + "name": "newOrderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "deactivateMarketProduct", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "removeMarketProduct", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "removeMarketProductGroup", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "lockCollateral", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "feeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskStateAcct", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LockCollateralParams" + } + } + ] + }, + { + "name": "unlockCollateral", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "feeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskStateAcct", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "LockCollateralParams" + } + } + ] + }, + { + "name": "initializePrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "operatorOwner", + "isMut": false, + "isSigner": true + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializePrintTradeParams" + } + } + ] + }, + { + "name": "initializePrintTradeExecutionOutput", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "executionOutput", + "isMut": true, + "isSigner": true + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "signPrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": true, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": true, + "isSigner": false + }, + { + "name": "operator", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "creatorTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "SignPrintTradeParams" + } + } + ] + }, + { + "name": "executePrintTrade", + "accounts": [ + { + "name": "op", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": true, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": true, + "isSigner": false + }, + { + "name": "operator", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "creatorTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "counterpartyTraderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + }, + { + "name": "executionOutput", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "cancelPrintTrade", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "closePrintTrade", + "accounts": [ + { + "name": "op", + "isMut": true, + "isSigner": true + }, + { + "name": "creator", + "isMut": false, + "isSigner": false + }, + { + "name": "counterparty", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "printTrade", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "seed", + "isMut": false, + "isSigner": false + }, + { + "name": "creatorWallet", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeTraderRiskGroup", + "accounts": [ + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": true + }, + { + "name": "traderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "closeTraderRiskGroup", + "accounts": [ + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "receiver", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "newOrder", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "traderFeeStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "referrerTrg", + "isMut": true, + "isSigner": false, + "docs": [ + "referrer_trg receives a programmatic percentage of taker fees", + "sdks route this back to the user's trg", + "frontends will want to route this to their own trg" + ] + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "NewOrderParams" + } + } + ] + }, + { + "name": "clearOpenOrders", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ClearOpenOrdersParams" + } + } + ] + }, + { + "name": "reinitializeTraderPositions", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setNumRiskStateAccounts", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "SetNumRiskStateAccountsParams" + } + } + ] + }, + { + "name": "updateVarianceCache", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "consumeOrderbookEvents", + "accounts": [ + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "rewardTarget", + "isMut": true, + "isSigner": true + }, + { + "name": "feeModelProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "feeModelConfigurationAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "feeOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "riskAndFeeSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ConsumeOrderbookEventsParams" + } + } + ] + }, + { + "name": "cancelOrder", + "accounts": [ + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CancelOrderParams" + } + } + ] + }, + { + "name": "depositFunds", + "accounts": [ + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "capitalLimits", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "DepositFundsParams" + } + } + ] + }, + { + "name": "withdrawFunds", + "accounts": [ + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": false, + "isSigner": true + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAcct", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimits", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "WithdrawFundsParams" + } + } + ] + }, + { + "name": "updateProductFunding", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateProductFundingParams" + } + } + ] + }, + { + "name": "updateProductMarkPriceConfig", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdateProductMarkPriceConfigParams" + } + } + ] + }, + { + "name": "transferFullPosition", + "accounts": [ + { + "name": "liquidator", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidateeRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidateeRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeCombo", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "InitializeComboParams" + } + } + ] + }, + { + "name": "updateTraderFunding", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "riskEngineProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "riskOutputRegister", + "isMut": true, + "isSigner": false + }, + { + "name": "traderRiskStateAccountInfo", + "isMut": true, + "isSigner": false + }, + { + "name": "riskModelConfigurationAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "riskSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "clearExpiredOrderbook", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + }, + { + "name": "bids", + "isMut": true, + "isSigner": false + }, + { + "name": "asks", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "ClearExpiredOrderbookParams" + } + } + ] + }, + { + "name": "popEvents", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "product", + "isMut": false, + "isSigner": false + }, + { + "name": "aaobProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "marketSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "orderbook", + "isMut": true, + "isSigner": false + }, + { + "name": "eventQueue", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PopEventsParams" + } + } + ] + }, + { + "name": "sweepFees", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "stakingFeeCollector", + "isMut": false, + "isSigner": false + }, + { + "name": "marketProductGroupVault", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollectorTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "stakingFeeCollectorTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "chooseSuccessor", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimAuthority", + "accounts": [ + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "newAuthority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "setupCapitalLimits", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimitsState", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateCapitalLimits", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "capitalLimitsState", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "CapitalLimitsParams" + } + } + ] + }, + { + "name": "updateTraderRiskGroup", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "traderFeeStateAcct", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateTraderRiskGroupOwner", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": false + }, + { + "name": "traderRiskGroup", + "isMut": true, + "isSigner": false + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "disableKillswitch", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "enableKillswitch", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "marketProductGroup", + "isMut": true, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "CapitalLimits", + "type": { + "kind": "struct", + "fields": [ + { + "name": "depositLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "withdrawalLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "MarketProductGroup", + "docs": [ + "The highest level organizational unit of the Dex.", + "Market product groups exist independently of each other.", + "i.e. each trader, product etc, corresponds to exactly one market product group." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "successor", + "type": "publicKey" + }, + { + "name": "vaultMint", + "type": "publicKey" + }, + { + "name": "collectedFees", + "type": { + "defined": "Fractional" + } + }, + { + "name": "feeCollector", + "type": "publicKey" + }, + { + "name": "decimals", + "type": "u64" + }, + { + "name": "riskEngineProgramId", + "type": "publicKey" + }, + { + "name": "feeModelProgramId", + "type": "publicKey" + }, + { + "name": "feeModelConfigurationAcct", + "type": "publicKey" + }, + { + "name": "riskModelConfigurationAcct", + "type": "publicKey" + }, + { + "name": "activeFlagsProducts", + "type": { + "defined": "Bitset" + } + }, + { + "name": "ewmaWindows", + "type": { + "array": [ + "u64", + 4 + ] + } + }, + { + "name": "marketProducts", + "type": { + "defined": "ProductArray" + } + }, + { + "name": "vaultBump", + "type": "u16" + }, + { + "name": "riskAndFeeBump", + "type": "u16" + }, + { + "name": "findFeesDiscriminantLen", + "type": "u16" + }, + { + "name": "validateAccountDiscriminantLen", + "type": "u16" + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountHealthDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountLiquidationDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxMakerFeeBps", + "type": "i16" + }, + { + "name": "minMakerFeeBps", + "type": "i16" + }, + { + "name": "maxTakerFeeBps", + "type": "i16" + }, + { + "name": "minTakerFeeBps", + "type": "i16" + }, + { + "name": "feeOutputRegister", + "type": "publicKey" + }, + { + "name": "riskOutputRegister", + "type": "publicKey" + }, + { + "name": "sequenceNumber", + "type": "u128" + }, + { + "name": "stakingFeeCollector", + "type": "publicKey" + }, + { + "name": "isKilled", + "type": "bool" + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "addressLookupTable", + "type": "publicKey" + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "ProductArray", + "type": { + "kind": "struct", + "fields": [ + { + "name": "array", + "type": { + "array": [ + { + "defined": "Product" + }, + 256 + ] + } + } + ] + } + }, + { + "name": "PrintTradeProduct", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTrade", + "type": { + "kind": "struct", + "fields": [ + { + "name": "isInitialized", + "type": "bool" + }, + { + "name": "creator", + "type": "publicKey" + }, + { + "name": "counterparty", + "type": "publicKey" + }, + { + "name": "seed", + "type": "publicKey" + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "numProducts", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operator", + "type": "publicKey" + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "isSigned", + "type": "bool" + }, + { + "name": "isCancelled", + "type": { + "defined": "CancelStatus" + } + }, + { + "name": "bump", + "type": "u8" + } + ] + } + }, + { + "name": "RiskOutputRegister", + "type": { + "kind": "struct", + "fields": [ + { + "name": "riskEngineOutput", + "type": { + "defined": "HealthResult" + } + } + ] + } + }, + { + "name": "TraderRiskGroup", + "docs": [ + "State account corresponding to a trader on a given market product group" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "marketProductGroup", + "type": "publicKey" + }, + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "activeProducts", + "type": { + "array": [ + "u8", + 128 + ] + } + }, + { + "name": "totalDeposited", + "type": { + "defined": "Fractional" + } + }, + { + "name": "totalWithdrawn", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cashBalance", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingCashBalance", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingFees", + "type": { + "defined": "Fractional" + } + }, + { + "name": "validUntil", + "type": "u64" + }, + { + "name": "makerFeeBps", + "type": "i32" + }, + { + "name": "takerFeeBps", + "type": "i32" + }, + { + "name": "traderPositions", + "type": { + "array": [ + { + "defined": "TraderPosition" + }, + 16 + ] + } + }, + { + "name": "riskStateAccount", + "type": "publicKey" + }, + { + "name": "feeStateAccount", + "type": "publicKey" + }, + { + "name": "clientOrderId", + "type": "u128" + }, + { + "name": "openOrders", + "type": { + "defined": "OpenOrders" + } + }, + { + "name": "lockedCollateral", + "type": { + "array": [ + { + "defined": "LockedCollateral" + }, + 16 + ] + } + }, + { + "name": "notionalMakerVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "notionalTakerVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "referredTakersNotionalVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "referralFees", + "docs": [ + "referral_fees is not necessarily REFERRER_FEES_PROPORTION * referred_takers_notional_volume,", + "because combo volume has only collects 1/8th the fees as outright volume" + ], + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTradeExecutionOutput", + "type": { + "kind": "struct", + "fields": [ + { + "name": "result", + "type": { + "defined": "PrintTradeExecutionResult" + } + } + ] + } + }, + { + "name": "CapitalLimitsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "depositLimit", + "type": { + "defined": "Fractional" + } + }, + { + "name": "withdrawalLimit", + "type": { + "defined": "Fractional" + } + } + ] + } + } + ], + "types": [ + { + "name": "LockedCollateralProductIndex", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "PrintTradeProductIndex", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "size", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "ProductArray", + "type": { + "kind": "struct", + "fields": [ + { + "name": "array", + "type": { + "array": [ + { + "defined": "Product" + }, + 256 + ] + } + } + ] + } + }, + { + "name": "Side", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Bid" + }, + { + "name": "Ask" + } + ] + } + }, + { + "name": "Params", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "CallBackInfo", + "docs": [ + "Buffer attached to aaob events to tie owner to events" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "userAccount", + "type": "publicKey" + }, + { + "name": "openOrdersIdx", + "type": "u64" + }, + { + "name": "orderNonce", + "type": "u128" + }, + { + "name": "clientOrderId", + "type": "u64" + } + ] + } + }, + { + "name": "TraderFees", + "type": { + "kind": "struct", + "fields": [ + { + "name": "validUntil", + "type": "i64" + }, + { + "name": "makerFeeBps", + "type": "i32" + }, + { + "name": "takerFeeBps", + "type": "i32" + } + ] + } + }, + { + "name": "TraderFeeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "isAggressor", + "type": "bool" + }, + { + "name": "matchedQuoteQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "matchedBaseQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "product", + "type": "publicKey" + } + ] + } + }, + { + "name": "PriceEwma", + "type": { + "kind": "struct", + "fields": [ + { + "name": "ewmaBid", + "type": { + "array": [ + { + "defined": "Fractional" + }, + 4 + ] + } + }, + { + "name": "ewmaAsk", + "type": { + "array": [ + { + "defined": "Fractional" + }, + 4 + ] + } + }, + { + "name": "bid", + "type": { + "defined": "Fractional" + } + }, + { + "name": "ask", + "type": { + "defined": "Fractional" + } + }, + { + "name": "slot", + "type": "u64" + }, + { + "name": "prevBid", + "type": { + "defined": "Fractional" + } + }, + { + "name": "prevAsk", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "OpenOrdersMetadata", + "type": { + "kind": "struct", + "fields": [ + { + "name": "askQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "bidQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "headIndex", + "type": "u64" + }, + { + "name": "numOpenOrders", + "type": "u64" + } + ] + } + }, + { + "name": "OpenOrders", + "type": { + "kind": "struct", + "fields": [ + { + "name": "freeListHead", + "type": "u64" + }, + { + "name": "totalOpenOrders", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "OpenOrdersMetadata" + }, + 256 + ] + } + }, + { + "name": "orders", + "type": { + "array": [ + { + "defined": "OpenOrdersNode" + }, + 1024 + ] + } + } + ] + } + }, + { + "name": "OpenOrdersNode", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u128" + }, + { + "name": "qty", + "type": "u64" + }, + { + "name": "clientId", + "type": "u64" + }, + { + "name": "prev", + "type": "u64" + }, + { + "name": "next", + "type": "u64" + } + ] + } + }, + { + "name": "Outright", + "docs": [ + "A market product corresponding to one underlying asset" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "metadata", + "type": { + "defined": "ProductMetadata" + } + }, + { + "name": "numRiskStateAccounts", + "docs": [ + "num_risk_state_accounts is the number of risk state accounts that have an untidied entry related to this product.", + "The DEX assumes that the attached risk engine will tidy (this likely means \"remove\")", + "risk entries related to this product during the first risk check after removing a TraderPosition." + ], + "type": "u64" + }, + { + "name": "productStatus", + "type": { + "defined": "ProductStatus" + } + }, + { + "name": "dust", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cumFundingPerShare", + "type": { + "defined": "Fractional" + } + }, + { + "name": "cumSocialLossPerShare", + "type": { + "defined": "Fractional" + } + }, + { + "name": "openLongInterest", + "type": { + "defined": "Fractional" + } + }, + { + "name": "openShortInterest", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceQualifyingCumValue", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceMaxQualifyingWidth", + "type": { + "defined": "Fractional" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u64", + 10 + ] + } + } + ] + } + }, + { + "name": "ProductMetadata", + "docs": [ + "Shared fields between Outright and Combo products" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u64" + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "orderbook", + "type": "publicKey" + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + }, + { + "name": "notionalTradedVolume", + "type": { + "defined": "Fractional" + } + }, + { + "name": "prices", + "type": { + "defined": "PriceEwma" + } + } + ] + } + }, + { + "name": "Combo", + "docs": [ + "A market product with multiple legs that are each outrights" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "metadata", + "type": { + "defined": "ProductMetadata" + } + }, + { + "name": "numLegs", + "type": "u64" + }, + { + "name": "legsArray", + "type": { + "array": [ + { + "defined": "Leg" + }, + 4 + ] + } + } + ] + } + }, + { + "name": "Leg", + "docs": [ + "One part of a combo. Each leg corresponds to an outright with the ratio determining", + "relative weighting" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "ratio", + "type": "i64" + } + ] + } + }, + { + "name": "HealthInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "health", + "type": { + "defined": "HealthStatus" + } + }, + { + "name": "action", + "type": { + "defined": "ActionStatus" + } + } + ] + } + }, + { + "name": "LiquidationInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "health", + "type": { + "defined": "HealthStatus" + } + }, + { + "name": "action", + "type": { + "defined": "ActionStatus" + } + }, + { + "name": "totalSocialLoss", + "type": { + "defined": "Fractional" + } + }, + { + "name": "liquidationPrice", + "type": { + "defined": "Fractional" + } + }, + { + "name": "socialLosses", + "type": { + "array": [ + { + "defined": "SocialLoss" + }, + 16 + ] + } + } + ] + } + }, + { + "name": "SocialLoss", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "amount", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "OrderInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "totalOrderQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "matchedOrderQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "orderSide", + "type": { + "defined": "Side" + } + }, + { + "name": "orderPrice", + "type": { + "defined": "Fractional" + } + }, + { + "name": "isCombo", + "type": "bool" + }, + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "operationType", + "type": { + "defined": "OperationType" + } + }, + { + "name": "oldAskQtyInBook", + "type": { + "defined": "Fractional" + } + }, + { + "name": "oldBidQtyInBook", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "TraderPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "productKey", + "type": "publicKey" + }, + { + "name": "position", + "type": { + "defined": "Fractional" + } + }, + { + "name": "pendingPosition", + "type": { + "defined": "Fractional" + } + }, + { + "name": "productIndex", + "type": "u64" + }, + { + "name": "lastCumFundingSnapshot", + "type": { + "defined": "Fractional" + } + }, + { + "name": "lastSocialLossSnapshot", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "LockedCollateral", + "docs": [ + "there is one LockedCollateral for each product; the array is in one-to-one mapping with trader_positions" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "tag", + "type": { + "defined": "AccountTag" + } + }, + { + "name": "askQty", + "type": { + "defined": "Fractional" + } + }, + { + "name": "bidQty", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "Bitset", + "type": { + "kind": "struct", + "fields": [ + { + "name": "inner", + "type": { + "array": [ + "u128", + 2 + ] + } + } + ] + } + }, + { + "name": "Fractional", + "docs": [ + "Fractional Operations" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "m", + "type": "i64" + }, + { + "name": "exp", + "type": "u64" + } + ] + } + }, + { + "name": "InitializeMarketProductGroupParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "validateAccountDiscriminantLen", + "type": "u64" + }, + { + "name": "findFeesDiscriminantLen", + "type": "u64" + }, + { + "name": "validateAccountHealthDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "validateAccountLiquidationDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "maxMakerFeeBps", + "type": "i16" + }, + { + "name": "minMakerFeeBps", + "type": "i16" + }, + { + "name": "maxTakerFeeBps", + "type": "i16" + }, + { + "name": "minTakerFeeBps", + "type": "i16" + } + ] + } + }, + { + "name": "UpdateMarketProductGroupParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "findFeesDiscriminantLen", + "type": "u16" + }, + { + "name": "findFeesDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "createFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeFeeStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + }, + { + "name": "closeRiskStateAccountDiscriminant", + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "InitializePrintTradeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "LockCollateralParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "LockedCollateralProductIndex" + }, + 6 + ] + } + } + ] + } + }, + { + "name": "SignPrintTradeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numProducts", + "type": "u64" + }, + { + "name": "products", + "type": { + "array": [ + { + "defined": "PrintTradeProductIndex" + }, + 6 + ] + } + }, + { + "name": "price", + "type": { + "defined": "Fractional" + } + }, + { + "name": "side", + "type": { + "defined": "Side" + } + }, + { + "name": "operatorCreatorFeeProportion", + "type": { + "defined": "Fractional" + } + }, + { + "name": "operatorCounterpartyFeeProportion", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "InitializeMarketProductParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "NewOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "side", + "docs": [ + "The order's side (Bid or Ask)" + ], + "type": { + "defined": "Side" + } + }, + { + "name": "maxBaseQty", + "docs": [ + "The max quantity of base token to match and post" + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "orderType", + "docs": [ + "The order type (supported types include Limit, FOK, IOC and PostOnly)" + ], + "type": { + "defined": "OrderType" + } + }, + { + "name": "matchLimit", + "docs": [ + "The maximum number of orders to be matched against.", + "Setting this number too high can sometimes lead to excessive resource consumption which can cause a failure." + ], + "type": "u64" + }, + { + "name": "limitPrice", + "docs": [ + "The order's limit price in ticks" + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "referrerFeeBps", + "docs": [ + "In addition to taker fees; routed to referrer_trg; can be zero", + "Should be used like this: 3bps -> use the value Fractional{ m: 3, exp: 4 }", + "Min: 0; Max: 100bps." + ], + "type": { + "defined": "Fractional" + } + }, + { + "name": "clientOrderId", + "docs": [ + "Order id that can be specified by client. Can be arbitrary u64. Defaults to the value 0." + ], + "type": "u64" + } + ] + } + }, + { + "name": "ClearOpenOrdersParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "productIndex", + "type": "u64" + } + ] + } + }, + { + "name": "SetNumRiskStateAccountsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numRiskStateAccounts", + "type": "u64" + } + ] + } + }, + { + "name": "ConsumeOrderbookEventsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxIterations", + "docs": [ + "The maximum number of events to consume" + ], + "type": "u64" + } + ] + } + }, + { + "name": "CancelOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "orderId", + "docs": [ + "The order_id of the order to cancel. Redundancy is used here to avoid having to iterate over all", + "open orders on chain. If order_id == 0, then client_order_id is used." + ], + "type": "u128" + }, + { + "name": "noErr", + "docs": [ + "do not fail when order is not found" + ], + "type": "bool" + }, + { + "name": "clientOrderId", + "docs": [ + "The client_order_id of the order to cancel. Used when order_id == 0." + ], + "type": "u64" + } + ] + } + }, + { + "name": "DepositFundsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "WithdrawFundsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quantity", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "UpdateProductFundingParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "Fractional" + } + }, + { + "name": "newProductStatus", + "type": { + "defined": "ProductStatus" + } + } + ] + } + }, + { + "name": "UpdateProductMarkPriceConfigParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "markPriceQualifyingCumValue", + "type": { + "defined": "Fractional" + } + }, + { + "name": "markPriceMaxQualifyingWidth", + "type": { + "defined": "Fractional" + } + } + ] + } + }, + { + "name": "InitializeComboParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 16 + ] + } + }, + { + "name": "tickSize", + "type": { + "defined": "Fractional" + } + }, + { + "name": "priceOffset", + "type": { + "defined": "Fractional" + } + }, + { + "name": "baseDecimals", + "type": "u64" + }, + { + "name": "ratios", + "type": { + "vec": "i8" + } + } + ] + } + }, + { + "name": "PopEventsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numEventsToPop", + "type": "u64" + } + ] + } + }, + { + "name": "ClearExpiredOrderbookParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "numOrdersToCancel", + "type": "u8" + } + ] + } + }, + { + "name": "DomainOrProgramError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "DexErr", + "fields": [ + { + "defined": "DexError" + } + ] + }, + { + "name": "UtilErr", + "fields": [ + { + "defined": "UtilError" + } + ] + }, + { + "name": "ProgramErr", + "fields": [ + { + "name": "msg", + "type": "string" + } + ] + }, + { + "name": "Other", + "fields": [ + { + "name": "code", + "type": "u32" + }, + { + "name": "msg", + "type": "string" + } + ] + } + ] + } + }, + { + "name": "UtilError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AccountAlreadyInitialized" + }, + { + "name": "AccountUninitialized" + }, + { + "name": "DuplicateProductKey" + }, + { + "name": "PublicKeyMismatch" + }, + { + "name": "AssertionError" + }, + { + "name": "InvalidMintAuthority" + }, + { + "name": "IncorrectOwner" + }, + { + "name": "PublicKeysShouldBeUnique" + }, + { + "name": "NotRentExempt" + }, + { + "name": "NumericalOverflow" + }, + { + "name": "RoundError" + }, + { + "name": "DivisionbyZero" + }, + { + "name": "InvalidReturnValue" + }, + { + "name": "SqrtRootError" + }, + { + "name": "ZeroPriceError" + }, + { + "name": "ZeroQuantityError" + }, + { + "name": "SerializeError" + }, + { + "name": "DeserializeError" + }, + { + "name": "InvalidBitsetIndex" + }, + { + "name": "PushToFullBitvec" + }, + { + "name": "U8MaxNotAllowedInBitvec" + } + ] + } + }, + { + "name": "DexError", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ContractIsExpired" + }, + { + "name": "ContractIsNotExpired" + }, + { + "name": "InvalidSystemProgramAccount" + }, + { + "name": "InvalidAobProgramAccount" + }, + { + "name": "InvalidStateAccountOwner" + }, + { + "name": "InvalidOrderIndex" + }, + { + "name": "UserAccountFull" + }, + { + "name": "TransactionAborted" + }, + { + "name": "MissingUserAccount" + }, + { + "name": "OrderNotFound" + }, + { + "name": "NoOp" + }, + { + "name": "OutofFunds" + }, + { + "name": "UserAccountStillActive" + }, + { + "name": "MarketStillActive" + }, + { + "name": "InvalidMarketSignerAccount" + }, + { + "name": "InvalidOrderbookAccount" + }, + { + "name": "InvalidMarketAdminAccount" + }, + { + "name": "InvalidBaseVaultAccount" + }, + { + "name": "InvalidQuoteVaultAccount" + }, + { + "name": "FullMarketProductGroup" + }, + { + "name": "MissingMarketProduct" + }, + { + "name": "InvalidWithdrawalAmount" + }, + { + "name": "InvalidTakerTrader" + }, + { + "name": "FundsError" + }, + { + "name": "InactiveProductError" + }, + { + "name": "TooManyOpenOrdersError" + }, + { + "name": "NoMoreOpenOrdersError" + }, + { + "name": "NonZeroPriceTickExponentError" + }, + { + "name": "DuplicateProductNameError" + }, + { + "name": "InvalidRiskResponseError" + }, + { + "name": "InvalidAccountHealthError" + }, + { + "name": "OrderbookIsEmptyError" + }, + { + "name": "CombosNotRemoved" + }, + { + "name": "AccountNotLiquidable" + }, + { + "name": "FundingPrecisionError" + }, + { + "name": "ProductDecimalPrecisionError" + }, + { + "name": "ProductNotOutright" + }, + { + "name": "ProductNotCombo" + }, + { + "name": "InvalidSocialLossCalculation" + }, + { + "name": "ProductIndexMismatch" + }, + { + "name": "InvalidOrderID" + }, + { + "name": "InvalidBytesForZeroCopyDeserialization" + }, + { + "name": "IncorrectPrintTradeSize" + }, + { + "name": "IncorrectPrintTradePrice" + }, + { + "name": "IncorrectPrintTradeSide" + }, + { + "name": "IncorrectPrintTradeOperatorCreatorFees" + }, + { + "name": "IncorrectPrintTradeOperatorCounterpartyFees" + }, + { + "name": "InvalidPrintTradeOperatorFees" + }, + { + "name": "DepositLimitExceeded" + }, + { + "name": "WithdrawLimitExceeded" + }, + { + "name": "NegativeDepositLimit" + }, + { + "name": "NegativeWithdrawLimit" + }, + { + "name": "DepositDeniedInsufficientBalanceOnWhitelistAtaToken" + }, + { + "name": "DepositDeclinedUnfrozenWhitelistAtaToken" + }, + { + "name": "DepositDeclinedNonExistentWhitelistAtaTokenOnTraderRiskGroup" + }, + { + "name": "InvalidProductStatusInUpdateFunding" + }, + { + "name": "ContractIsNotExpiring" + }, + { + "name": "ContractHasNonZeroOpenInterest" + }, + { + "name": "ContractHasNonZeroOpenInterestOrRiskStateAccounts" + }, + { + "name": "ContractIsActive" + }, + { + "name": "FailedToGetOrderQuantity" + }, + { + "name": "SelfTradeBehaviorDecrementTakeIsDisallowed" + }, + { + "name": "PriceBandViolation" + }, + { + "name": "UnexpectedImbalancedOpenInterest" + }, + { + "name": "MaximumOpenInterestExceeded" + }, + { + "name": "MarketProductGroupKillswitchIsOn" + }, + { + "name": "InvalidFutureExpiry" + }, + { + "name": "MaxReferrerFeeBpsExceeded" + }, + { + "name": "PrintTradeOperatorDidNotSign" + }, + { + "name": "PrintTradeInvalidProductsLength" + }, + { + "name": "ContractIsNotActive" + }, + { + "name": "PrintTradeInvalidNumProducts" + }, + { + "name": "PrintTradeProductMismatch" + }, + { + "name": "InsufficientLockedCollateral" + }, + { + "name": "OracleNotWhitelisted" + } + ] + } + }, + { + "name": "AccountTag", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "MarketProductGroup" + }, + { + "name": "TraderRiskGroup" + }, + { + "name": "TraderPosition" + }, + { + "name": "MarketProductGroupWithCombos" + }, + { + "name": "ComboGroup" + }, + { + "name": "Combo" + }, + { + "name": "RiskProfile" + }, + { + "name": "LockedCollateral" + } + ] + } + }, + { + "name": "ProductStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Uninitialized" + }, + { + "name": "Initialized" + }, + { + "name": "Expired" + }, + { + "name": "Expiring" + } + ] + } + }, + { + "name": "OrderType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Limit" + }, + { + "name": "ImmediateOrCancel" + }, + { + "name": "FillOrKill" + }, + { + "name": "PostOnly" + } + ] + } + }, + { + "name": "CancelStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Active" + }, + { + "name": "CreatorCancelled" + }, + { + "name": "CounterpartyCancelled" + } + ] + } + }, + { + "name": "Product", + "docs": [ + "Unify Outright and Combo" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Outright", + "fields": [ + { + "name": "outright", + "type": { + "defined": "Outright" + } + } + ] + }, + { + "name": "Combo", + "fields": [ + { + "name": "combo", + "type": { + "defined": "Combo" + } + } + ] + } + ] + } + }, + { + "name": "OperationType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "NewOrder" + }, + { + "name": "CancelOrder" + }, + { + "name": "CheckHealth" + }, + { + "name": "PositionTransfer" + }, + { + "name": "ConsumeEvents" + }, + { + "name": "CheckWithdrawalHealth" + }, + { + "name": "LockCollateral" + }, + { + "name": "SignPrinTrade" + } + ] + } + }, + { + "name": "HealthResult", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Health", + "fields": [ + { + "name": "health_info", + "type": { + "defined": "HealthInfo" + } + } + ] + }, + { + "name": "Liquidation", + "fields": [ + { + "name": "liquidation_info", + "type": { + "defined": "LiquidationInfo" + } + } + ] + } + ] + } + }, + { + "name": "HealthStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Healthy" + }, + { + "name": "Unhealthy" + }, + { + "name": "Liquidatable" + }, + { + "name": "NotLiquidatable" + } + ] + } + }, + { + "name": "ActionStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Approved" + }, + { + "name": "NotApproved" + } + ] + } + }, + { + "name": "PrintTradeExecutionResult", + "type": { + "kind": "enum", + "variants": [ + { + "name": "CounterpartyHasntSigned" + }, + { + "name": "CreatorCancelled" + }, + { + "name": "CounterpartyCancelled" + }, + { + "name": "CreatorNotEnoughLockedCollateral" + }, + { + "name": "CounterpartyNotEnoughLockedCollateral" + }, + { + "name": "Success" + } + ] + } + } + ], + "events": [ + { + "name": "DexOrderSummary", + "fields": [ + { + "name": "postedOrderId", + "type": { + "option": "u128" + }, + "index": false + }, + { + "name": "totalBaseQty", + "type": "u64", + "index": false + }, + { + "name": "totalQuoteQty", + "type": "u64", + "index": false + }, + { + "name": "totalBaseQtyPosted", + "type": "u64", + "index": false + } + ] + } + ] +} \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/keypairs/operator-trg-risk-state.json b/packages/validator/dependencies/hxro/keypairs/operator-trg-risk-state.json new file mode 100644 index 000000000..f6df6551b --- /dev/null +++ b/packages/validator/dependencies/hxro/keypairs/operator-trg-risk-state.json @@ -0,0 +1 @@ +[140,178,122,123,227,247,157,74,161,95,3,229,95,104,226,238,52,99,225,143,191,9,207,105,165,96,181,108,122,42,224,92,84,158,145,6,32,178,169,177,129,126,50,241,104,37,63,149,247,11,107,47,229,67,102,38,124,59,72,103,2,43,159,205] \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/keypairs/operator-trg.json b/packages/validator/dependencies/hxro/keypairs/operator-trg.json new file mode 100644 index 000000000..5d9fa53ae --- /dev/null +++ b/packages/validator/dependencies/hxro/keypairs/operator-trg.json @@ -0,0 +1 @@ +[168,232,99,222,141,177,104,101,96,34,154,127,107,161,69,146,61,70,137,231,19,89,170,99,230,152,30,139,167,26,198,40,43,19,34,66,232,78,251,245,249,45,22,99,93,237,77,172,8,223,244,200,34,239,11,197,250,204,83,185,19,165,141,176] \ No newline at end of file diff --git a/packages/validator/dependencies/hxro/programs/aaob_DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b.so b/packages/validator/dependencies/hxro/programs/aaob_DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b.so new file mode 100644 index 000000000..f07616264 Binary files /dev/null and b/packages/validator/dependencies/hxro/programs/aaob_DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b.so differ diff --git a/packages/validator/dependencies/hxro/programs/constant_fees.so b/packages/validator/dependencies/hxro/programs/constant_fees.so new file mode 100755 index 000000000..5ef894b2c Binary files /dev/null and b/packages/validator/dependencies/hxro/programs/constant_fees.so differ diff --git a/packages/validator/dependencies/hxro/programs/dex_FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL.so b/packages/validator/dependencies/hxro/programs/dex_FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL.so new file mode 100644 index 000000000..c9ec58625 Binary files /dev/null and b/packages/validator/dependencies/hxro/programs/dex_FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL.so differ diff --git a/packages/validator/dependencies/hxro/programs/instrument_8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq.so b/packages/validator/dependencies/hxro/programs/instrument_8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq.so new file mode 100644 index 000000000..a7095159e Binary files /dev/null and b/packages/validator/dependencies/hxro/programs/instrument_8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq.so differ diff --git a/packages/validator/dependencies/hxro/programs/noop_risk_engine.so b/packages/validator/dependencies/hxro/programs/noop_risk_engine.so new file mode 100755 index 000000000..1dffbf099 Binary files /dev/null and b/packages/validator/dependencies/hxro/programs/noop_risk_engine.so differ diff --git a/packages/validator/dependencies/hxro/pubkey-naming.json b/packages/validator/dependencies/hxro/pubkey-naming.json new file mode 100644 index 000000000..e5ae78175 --- /dev/null +++ b/packages/validator/dependencies/hxro/pubkey-naming.json @@ -0,0 +1,22 @@ +{ + "12fr3WXr7Mh1wGMPQe1qe5VUeexz1BRzJ6SfAhHPgC1b": "taker-fee-state", + "3fw72yL2pG7cKmPs4TYJa6C9496NyypFpj5UQVLe515j": "product-0", + "3q4UnqSY7ARzcbX8B647soB5Xji4Qr23idLQGpZGLzJa": "product-1-orderbook", + "4Lrt2YtUyEB8SrtTR3Tsb1DBGU9hRU6xNuDZd9zJrKG9": "maker-trg", + "4Ucpj5hWiz8msBQVgFSUnqxQCkJWEPn5YbpwFbbhxoa6": "fee-output", + "5T9ApZtB3yTKRv6ssmHdr15hB3d9XnA3WwrYAZTScetY": "risk-config", + "5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV": "fees-program", + "6Prp1p7vjS6LCb8xR1oQqsbUPX9AWaHz9PBVbdzAFHT4": "execution-output", + "78haJHMHdjdp6phofBzQwbHdNobFyYDrGRdgfAWQfwxL": "taker-risk-state", + "8qBD1ZewtfoxNAy3E45f5fRtwQUhLku55cVVxT5cMPef": "product-1", + "A3tmPza8B4rvHFiUkPHLsL7Nnv4ERK8utFfwPa1yAn18": "taker-trg", + "BVDTB61eHY7UnCb4ueatdaV4rctTzqfLAL6sQDeMNSHA": "risk-program", + "CTc7swEKXFCD1gsnvVcQyozXK2zJ3roQr3fuU7G6uerC": "product-0-orderbook", + "EDHbf67fJZBZoKFJGPEC7b9qimnave5DiYBctVWEysYb": "maker-risk-state", + "FEaUEZkFnyTfkWm8GgYR7sbyMkoW5nYSyqECDmKfQQoo": "risk-output", + "FU68EKUppMq89TSVBELYpbsdw2FpzKwx79mPvCARmM9t": "maker-fee-state", + "FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL": "dex-program", + "G6b2JSF5M7SySosNC4GkHHmqXczSCGUycppRiYvTQ7aK": "vault", + "GBhshm4LFyYTv9iPocz7kmLpRhvvPNoxH9wgB57uNamm": "fee-config", + "GCXr6LDZurWK8Hkm18gZzJ7jUgvrYEVFFeWUR346fd42": "mpg" +} \ No newline at end of file diff --git a/packages/validator/fixtures/accounts/hxro-print-trade-provider-config.json b/packages/validator/fixtures/accounts/hxro-print-trade-provider-config.json new file mode 100644 index 000000000..2de1c4e92 --- /dev/null +++ b/packages/validator/fixtures/accounts/hxro-print-trade-provider-config.json @@ -0,0 +1,13 @@ +{ + "pubkey": "GizbUy6geL8B6jWGrnkH7jYvExBhpSpEzMyvx9hZfaho", + "account": { + "lamports": 1169280, + "data": [ + "mwyq4B76zILh05IpcF4Uyf+vsSOCQd79Yzo2cN7taTwXsxHuZE4XXw==", + "base64" + ], + "owner": "4WbVwc5Edfo3oB1n16bVC9qrghYHSNh1qAECbSCyiT95", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/fixtures/accounts/rfq-base-asset-btc.json b/packages/validator/fixtures/accounts/rfq-base-asset-btc.json index 693a2d8b9..ad6e19d7f 100644 --- a/packages/validator/fixtures/accounts/rfq-base-asset-btc.json +++ b/packages/validator/fixtures/accounts/rfq-base-asset-btc.json @@ -1,12 +1,12 @@ { - "pubkey": "D3AV2d2Dpf54BPqvJ7pNfuzWboFFY4tNH8U6Me5Jz44y", + "pubkey": "9WJ5B36cb23UVuTGAw3cF3PdkwYcpRd3or9NB2feXob2", "account": { "lamports": 2804880, "data": [ - "A/5kN3P/Bxf/AAABAABujEl3g94AWWT2ktFbxNUQIrF1jMwAhCmERj8Lf9/+nwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAEJUQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "A/5kN3P/Bxf+AAABAABujEl3g94AWWT2ktFbxNUQIrF1jMwAhCmERj8Lf9/+nwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAEJUQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-base-asset-eth.json b/packages/validator/fixtures/accounts/rfq-base-asset-eth.json index d9fdd78e4..895db8962 100644 --- a/packages/validator/fixtures/accounts/rfq-base-asset-eth.json +++ b/packages/validator/fixtures/accounts/rfq-base-asset-eth.json @@ -1,12 +1,12 @@ { - "pubkey": "CjN93gP6pPLNyEmKaSbkikSQuw9TY5Xy8MoqE5UCwDPR", + "pubkey": "CtUPSK5cXRmsr1wGo5nCjfHQ9Dca6hsg26FBiZcMsTVp", "account": { "lamports": 2804880, "data": [ - "A/5kN3P/Bxf/AgABAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAEVUSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "A/5kN3P/Bxf8AgABAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAEVUSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-base-asset-sol.json b/packages/validator/fixtures/accounts/rfq-base-asset-sol.json index 363e2a2c4..0426f9e1d 100644 --- a/packages/validator/fixtures/accounts/rfq-base-asset-sol.json +++ b/packages/validator/fixtures/accounts/rfq-base-asset-sol.json @@ -1,12 +1,12 @@ { - "pubkey": "FkyRgBpQZNuxgYZpnrg6bg1s3TTSN7fmyoELcFQwmacD", + "pubkey": "7RMoZT2GLMvT5LiuXL9gSPcHdwEsS9f8Gi116cQ9ydNv", "account": { "lamports": 2804880, "data": [ - "A/5kN3P/Bxf8AQABAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8Ni2/aLOukHaFdQJXR2jkqDS+O0MbHvA9M+sjCgLVtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAFNPTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "A/5kN3P/Bxf/AQABAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8Ni2/aLOukHaFdQJXR2jkqDS+O0MbHvA9M+sjCgLVtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAFNPTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-collateral-info-dao.json b/packages/validator/fixtures/accounts/rfq-collateral-info-dao.json index 9563912e3..7299a5457 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-info-dao.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-info-dao.json @@ -1,12 +1,12 @@ { - "pubkey": "GwzpnXhzMNSgLdNJXKtyLB9ZbSiwFTDdomBh4UnVB5Q2", + "pubkey": "ADSmGasDML6HXpRxACYjAqWz8icFib4hztZ6YF3vNtH6", "account": { "lamports": 3062400, "data": [ - "o0RSJdyyEpn7ZJJsMbdIfexWonT9yyqMxu1HHDD0uX9BX7OXjafeIJn/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "o0RSJdyyEpn9ZJJsMbdIfexWonT9yyqMxu1HHDD0uX9BX7OXjafeIJn/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-collateral-info-maker.json b/packages/validator/fixtures/accounts/rfq-collateral-info-maker.json index 8f133aac6..7790bd8cc 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-info-maker.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-info-maker.json @@ -1,12 +1,12 @@ { - "pubkey": "B8cMG9jrUgcUS2FdZfJLEnjFhL828WvhE8xTqfM1xDSK", + "pubkey": "48qiMm1RzkdLJ4HT63pwB2LXtUo8Z9idwJouQpeTwhfR", "account": { "lamports": 3062400, "data": [ - "o0RSJdyyEpn/RGcv6WZ5nR0SQFCdXFvcEqmvImWuWJkw9t9ogVLKIbf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "o0RSJdyyEpn9RGcv6WZ5nR0SQFCdXFvcEqmvImWuWJkw9t9ogVLKIbf9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-collateral-info-taker.json b/packages/validator/fixtures/accounts/rfq-collateral-info-taker.json index 4a7f4a297..f8b04e5a8 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-info-taker.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-info-taker.json @@ -1,12 +1,12 @@ { - "pubkey": "5Xpck9sewCtS1KBECyHonaLErZT9C1Cnve11W5TWLRCH", + "pubkey": "8k1Pv1RjECRindE1PVzBuoVMUZz8mNFxrGj5oSMFiyiu", "account": { "lamports": 3062400, "data": [ - "o0RSJdyyEpn/yxkDb26bL0vjVHOsyuI/i4PC7QTivY42lYqpvanXNlf7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "o0RSJdyyEpn/yxkDb26bL0vjVHOsyuI/i4PC7QTivY42lYqpvanXNlf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-collateral-token-dao.json b/packages/validator/fixtures/accounts/rfq-collateral-token-dao.json index 21f9e1664..8d507d16d 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-token-dao.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-token-dao.json @@ -1,9 +1,9 @@ { - "pubkey": "6A4Zb6yNp8g7nfSY6kJPtrozDfKjJo1dAL1JQuoKpwHd", + "pubkey": "Bc7HGjyAymBhA1xHPZpnGMnaju6jiYThMvvbo8qWpVE8", "account": { "lamports": 2039280, "data": [ - "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZuns9gyb560QSE+xCnX/2taeg+WJKxx/syFzd8sOLafudwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZumI6UhbtanKC+A8hLXGGONU15fCDohQWp9tIILPO2Z8qQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/packages/validator/fixtures/accounts/rfq-collateral-token-maker.json b/packages/validator/fixtures/accounts/rfq-collateral-token-maker.json index 66c05b7cd..0ab4cc3f4 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-token-maker.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-token-maker.json @@ -1,9 +1,9 @@ { - "pubkey": "EK4QgzVVh3xCwhUSA7rYQuXXEw55jSnjhk6WRoqqKV2s", + "pubkey": "Eu5Ckc6jV6MMPtQLkNWMr3g3kd1oTXhfYL5nqTdH8hqy", "account": { "lamports": 2039280, "data": [ - "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZumWh+eQKJUVQ3K7T57fvQBRB5ibV6Eu3TGmP3WqFZmsBACAxqR+jQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZukulTTcGjEatA0bElqKOcJgF7+0QBWQ98HZ9bcSzFhZxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/packages/validator/fixtures/accounts/rfq-collateral-token-taker.json b/packages/validator/fixtures/accounts/rfq-collateral-token-taker.json index 9d21e3ad6..926239dd0 100644 --- a/packages/validator/fixtures/accounts/rfq-collateral-token-taker.json +++ b/packages/validator/fixtures/accounts/rfq-collateral-token-taker.json @@ -1,9 +1,9 @@ { - "pubkey": "2ChcGSXg2kB2UaPbicxyraTTTuPzaUppioSYiUungodw", + "pubkey": "4Ebb8C6qYMYa9Cup7fHsWkdU8J5qxXfXoUoPcgAqYJ8c", "account": { "lamports": 2039280, "data": [ - "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZulDVAMKF8UfyoBiSzIX9GhRItPnJYfDvOYXpImeivHxdgCAxqR+jQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "aRq5Tm95/2xFlF3S5PgBarK9se95mD6qo+5+Z1sAZulzBjrf5+5kFb4+wKYfJ3Z82zackn0hmZ6o+dj/AnA8ZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", diff --git a/packages/validator/fixtures/accounts/rfq-mint-info-btc.json b/packages/validator/fixtures/accounts/rfq-mint-info-btc.json index ce930aaa8..b2b8db099 100644 --- a/packages/validator/fixtures/accounts/rfq-mint-info-btc.json +++ b/packages/validator/fixtures/accounts/rfq-mint-info-btc.json @@ -1,12 +1,12 @@ { - "pubkey": "46iUXCqyuVhoN9hpdETa6eyhbMDLQh3HjbpKS2FmygE7", + "pubkey": "CCGguC4YFVLr17tM317mbqvechmgZvH1To5BcKi43GXX", "account": { "lamports": 2324640, "data": [ - "x3PV3dsdh6791QdAbyji9GYRbBJEIDGa7a7Ri6BXDdP2m5O+Zgs5buYJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "x3PV3dsdh67/1QdAbyji9GYRbBJEIDGa7a7Ri6BXDdP2m5O+Zgs5buYJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-mint-info-eth.json b/packages/validator/fixtures/accounts/rfq-mint-info-eth.json index b31642f1f..0a1081111 100644 --- a/packages/validator/fixtures/accounts/rfq-mint-info-eth.json +++ b/packages/validator/fixtures/accounts/rfq-mint-info-eth.json @@ -1,12 +1,12 @@ { - "pubkey": "CzMVe1ZbzCp1BdRYezghVzBsXoiZgBAodbR33gu8WTFC", + "pubkey": "F74ZnvhTmF9JRJ9LCQ6kxfkSUXaLfHy9dxMnavpGWkBT", "account": { "lamports": 2324640, "data": [ - "x3PV3dsdh67/KOeZ7XiJHyjoRFaYKs+85ejjnJrjfLSWJ2Uf3N+pjqwJAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "x3PV3dsdh67+KOeZ7XiJHyjoRFaYKs+85ejjnJrjfLSWJ2Uf3N+pjqwJAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-mint-info-sol.json b/packages/validator/fixtures/accounts/rfq-mint-info-sol.json index 66c3e8262..4ecc6e389 100644 --- a/packages/validator/fixtures/accounts/rfq-mint-info-sol.json +++ b/packages/validator/fixtures/accounts/rfq-mint-info-sol.json @@ -1,12 +1,12 @@ { - "pubkey": "H75NkwkmBuom83nuqQwyuqQZQQuyue59frfmgc5QALXv", + "pubkey": "4foY3PJTrLUt4nPJuuQy7WuRKz6kJXCuLBwxXdmSYgP2", "account": { "lamports": 2324640, "data": [ - "x3PV3dsdh67/KOWejuQHeNYncgTtjfJmQZMafgdeEmJ0ZWn5c9DFHpsJAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "x3PV3dsdh67+KOWejuQHeNYncgTtjfJmQZMafgdeEmJ0ZWn5c9DFHpsJAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-mint-info-usd-quote.json b/packages/validator/fixtures/accounts/rfq-mint-info-usd-quote.json index f9c21fd34..d12db6387 100644 --- a/packages/validator/fixtures/accounts/rfq-mint-info-usd-quote.json +++ b/packages/validator/fixtures/accounts/rfq-mint-info-usd-quote.json @@ -1,12 +1,12 @@ { - "pubkey": "2eDUTTPjPs8CusiikNDG4rWSZvaVPbodkJrU9bNDYiSX", + "pubkey": "3UV85jwjPmdL71q2kXiPZQbnz8N9CiYbvKadzaNhxX6W", "account": { "lamports": 2324640, "data": [ "x3PV3dsdh67/e2UTGuRioXUH1thtTs+0Qj7hdyxRnoHwm55RQpy8WkYJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/rfq-protocol.json b/packages/validator/fixtures/accounts/rfq-protocol.json index 9aefb2b96..a7af7d43d 100644 --- a/packages/validator/fixtures/accounts/rfq-protocol.json +++ b/packages/validator/fixtures/accounts/rfq-protocol.json @@ -1,12 +1,12 @@ { - "pubkey": "9xcYm9iSMH5aw7dQQBb711wpy3fYLEPfsNhbiJM4yqkU", + "pubkey": "GjDjkE8YnpE4ugQGg2E7qbDnFn1eb6DP9FEWbT22UPxy", "account": { - "lamports": 33895200, + "lamports": 35245440, "data": [ - "ITOthiOMw/hkkmwxt0h97FaidP3LKozG7UccMPS5f0Ffs5eNp94gmf4BAC0xAQAAAACAlpgAAAAAAADh9QUAAAAAAGXNHQAAAABXDOQgzydMH+ZRgmUiu2l19Vnyq1wVR35OLdD4mObdU2kauU5vef9sRZRd0uT4AWqyvbHveZg+qqPufmdbAGbpAwAAAK5NLOfqYWrHRlUywKtjfd8qcXIG2SdJ6CJsOcSdStteAQEBBwMDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh4qn7+zq+3cWnlFlgi9vA6gec0len/0P5uUkxxsJr6ABAAIHAwMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOtklH0CoWMHYr5p2cci65zXOxIf9IrHFBBI3NCo6bSwEAAwcDAwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "ITOthiOMw/hkkmwxt0h97FaidP3LKozG7UccMPS5f0Ffs5eNp94gmf8BAC0xAQAAAACAlpgAAAAAAADh9QUAAAAAAGXNHQAAAADQutL19LeRkX2pDq//ZKenRFnb6euxETuTU5Jt1XnnzWkauU5vef9sRZRd0uT4AWqyvbHveZg+qqPufmdbAGbpAQAAADQn6ZFuvjtDiVsOoxh64YjkrChPKmO+L68J8EWlRROEAgEDAAAALuq50RD25+XaanAnJ+aMkEeElLwt95Vm39LCpn1oGNYBAQEHBQMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABM4YvEy7sm/n6dRhS0YyinN5+xEyNX+eTyt9D/sMg3UQEAAgcDAwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPHE8jZWWx+0DKPG8mlku8p0YsMeTFUt2dJYH3yGio9fAQADBwMDBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "base64" ], - "owner": "J7WkE9mTzwTo3pjxENdrH7sekZPrN2VYNpk1pgfZxVr9", + "owner": "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/risk-engine-config.json b/packages/validator/fixtures/accounts/risk-engine-config.json index 9ac0d1cf9..fa8083902 100644 --- a/packages/validator/fixtures/accounts/risk-engine-config.json +++ b/packages/validator/fixtures/accounts/risk-engine-config.json @@ -1,12 +1,12 @@ { - "pubkey": "5tpJhxJTEh49PH3Q1hhDG3nNjoeJ1vW1iCqVe8rqe83D", + "pubkey": "66TqCm7S1tEjC96TEggh2EpcYdmAppZy3qHLapP3peX", "account": { - "lamports": 23274240, + "lamports": 9744000, "data": [ - "mwyq4B76zIIAypo7AAAAAACUNXcAAAAACQAAAAAAAAB7FK5H4XqEP5qZmZmZmbk/AAPMEgAAAAB7FK5H4XqEPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACamZmZmZmpPwAAAAAAAOA/exSuR+F6lD+amZmZmZnJP3sUrkfheqQ/MzMzMzMz0z97FK5H4Xq0P5qZmZmZmdk/uB6F61G4vj8AAAAAAADgP5qZmZmZmck/MzMzMzMz4z8zMzMzMzPTP2ZmZmZmZuY/mpmZmZmZqT+amZmZmZnpP3sUrkfheqQ/mpmZmZmZ2T97FK5H4Xq0PzMzMzMzM+M/exSuR+F6xD+amZmZmZnpP7gehetRuM4/AAAAAAAA8D+amZmZmZnZPzMzMzMzM/M/MzMzMzMz4z9mZmZmZmb2P5qZmZmZmak/MzMzMzMz8z+4HoXrUbiuPzMzMzMzM+M/uB6F61G4vj/NzMzMzMzsP7gehetRuM4/MzMzMzMz8z8K16NwPQrXPwAAAAAAAPg/MzMzMzMz4z/NzMzMzMz8P83MzMzMzOw/zczMzMzMAECamZmZmZmpPzMzMzMzMwNAexSuR+F6tD+amZmZmZnpP3sUrkfhesQ/MzMzMzMz8z97FK5H4XrUP5qZmZmZmfk/uB6F61G43j8AAAAAAAAAQJqZmZmZmek/MzMzMzMzA0AzMzMzMzPzP2ZmZmZmZgZAmpmZmZmZqT8AAAAAAAAUQJqZmZmZmbk/AAAAAAAA8D+amZmZmZnJPwAAAAAAAPg/mpmZmZmZ2T8AAAAAAAAAQDMzMzMzM+M/AAAAAAAABEAAAAAAAADwPwAAAAAAAAhAAAAAAAAA+D8AAAAAAAAMQJqZmZmZmak/AAAAAAAAJECamZmZmZnJPwAAAAAAAOA/MzMzMzMz0z8AAAAAAADgP5qZmZmZmdk/AAAAAAAA4D8AAAAAAADgPwAAAAAAAOA/MzMzMzMz4z8AAAAAAADgP2ZmZmZmZuY/AAAAAAAA4D+amZmZmZmpPwAAAAAAAC5AmpmZmZmZyT8AAAAAAADgPzMzMzMzM9M/AAAAAAAA4D+amZmZmZnZPwAAAAAAAOA/AAAAAAAA4D8AAAAAAADgPzMzMzMzM+M/AAAAAAAA4D9mZmZmZmbmPwAAAAAAAOA/mpmZmZmZqT8AAAAAAAA0QJqZmZmZmck/AAAAAAAA4D8zMzMzMzPTPwAAAAAAAOA/mpmZmZmZ2T8AAAAAAADgPwAAAAAAAOA/AAAAAAAA4D8zMzMzMzPjPwAAAAAAAOA/ZmZmZmZm5j8AAAAAAADgP65NLOfqYWrHRlUywKtjfd8qcXIG2SdJ6CJsOcSdStteAAAAAAAAAACHiqfv7Or7dxaeUWWCL28DqB5zSV6f/Q/m5STHGwmvoAEAAAAAAAAATrZJR9AqFjB2K+adnHIuuc1zsSH/SKxxQQSNzQqOm0sBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "mwyq4B76zIIAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMEgAAAAB7FK5H4XqEPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "base64" ], - "owner": "6rosVyXKwj9tiHubXUBTguaCELsci4pBEuiRy36Lbz1p", + "owner": "F3o2hWqv61TavHuZYuStvW2Zd3M1JnoqBmmgGU77LRTr", "executable": false, "rentEpoch": 0 } diff --git a/packages/validator/fixtures/accounts/spot-instrument-config.json b/packages/validator/fixtures/accounts/spot-instrument-config.json new file mode 100644 index 000000000..c527ef432 --- /dev/null +++ b/packages/validator/fixtures/accounts/spot-instrument-config.json @@ -0,0 +1,13 @@ +{ + "pubkey": "ETU5oAWiE1pembP8LGvtB3Jung9XnMNc5B9Qjiasqign", + "account": { + "lamports": 1002240, + "data": [ + "mwyq4B76zIKAlpgAAAAAAA==", + "base64" + ], + "owner": "4A9M7iojGDPc4n4YDGnTmsYsNKUohG1zM1nrAqVMMmrm", + "executable": false, + "rentEpoch": 0 + } +} \ No newline at end of file diff --git a/packages/validator/fixtures/programs/euro_primitive.so b/packages/validator/fixtures/programs/euro_primitive.so deleted file mode 100755 index 59d6897a8..000000000 Binary files a/packages/validator/fixtures/programs/euro_primitive.so and /dev/null differ diff --git a/packages/validator/fixtures/programs/hxro_print_trade_provider.so b/packages/validator/fixtures/programs/hxro_print_trade_provider.so new file mode 100755 index 000000000..80ddc8995 Binary files /dev/null and b/packages/validator/fixtures/programs/hxro_print_trade_provider.so differ diff --git a/packages/validator/fixtures/programs/pseudo_pyth.so b/packages/validator/fixtures/programs/pseudo_pyth.so deleted file mode 100755 index 87aec20b7..000000000 Binary files a/packages/validator/fixtures/programs/pseudo_pyth.so and /dev/null differ diff --git a/packages/validator/fixtures/programs/pseudo_pyth_idl.ts b/packages/validator/fixtures/programs/pseudo_pyth_idl.ts deleted file mode 100644 index f785eb206..000000000 --- a/packages/validator/fixtures/programs/pseudo_pyth_idl.ts +++ /dev/null @@ -1,173 +0,0 @@ -export type Pyth = { - "version": "0.1.0", - "name": "pyth", - "instructions": [ - { - "name": "initialize", - "accounts": [ - { - "name": "price", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "price", - "type": "i64" - }, - { - "name": "expo", - "type": "i32" - }, - { - "name": "conf", - "type": "u64" - } - ] - }, - { - "name": "setPrice", - "accounts": [ - { - "name": "price", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "price", - "type": "i64" - } - ] - }, - { - "name": "getPrice", - "accounts": [ - { - "name": "price", - "isMut": false, - "isSigner": false - }, - { - "name": "dataAccount", - "isMut": true, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - } - ], - "accounts": [ - { - "name": "dataAccount", - "type": { - "kind": "struct", - "fields": [ - { - "name": "price", - "type": "u64" - } - ] - } - } - ] -}; - -export const IDL: Pyth = { - "version": "0.1.0", - "name": "pyth", - "instructions": [ - { - "name": "initialize", - "accounts": [ - { - "name": "price", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "price", - "type": "i64" - }, - { - "name": "expo", - "type": "i32" - }, - { - "name": "conf", - "type": "u64" - } - ] - }, - { - "name": "setPrice", - "accounts": [ - { - "name": "price", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "price", - "type": "i64" - } - ] - }, - { - "name": "getPrice", - "accounts": [ - { - "name": "price", - "isMut": false, - "isSigner": false - }, - { - "name": "dataAccount", - "isMut": true, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - } - ], - "accounts": [ - { - "name": "dataAccount", - "type": { - "kind": "struct", - "fields": [ - { - "name": "price", - "type": "u64" - } - ] - } - } - ] -}; diff --git a/packages/validator/fixtures/programs/psyoptions_american_instrument.so b/packages/validator/fixtures/programs/psyoptions_american_instrument.so index 284c8e364..45ef0b640 100755 Binary files a/packages/validator/fixtures/programs/psyoptions_american_instrument.so and b/packages/validator/fixtures/programs/psyoptions_american_instrument.so differ diff --git a/packages/validator/fixtures/programs/psyoptions_european_instrument.so b/packages/validator/fixtures/programs/psyoptions_european_instrument.so index 20e99782f..9e7addc23 100755 Binary files a/packages/validator/fixtures/programs/psyoptions_european_instrument.so and b/packages/validator/fixtures/programs/psyoptions_european_instrument.so differ diff --git a/packages/validator/fixtures/programs/rfq.so b/packages/validator/fixtures/programs/rfq.so index 203ee8a1e..089d185e3 100755 Binary files a/packages/validator/fixtures/programs/rfq.so and b/packages/validator/fixtures/programs/rfq.so differ diff --git a/packages/validator/fixtures/programs/risk_engine.so b/packages/validator/fixtures/programs/risk_engine.so index 2e31bd6cf..b8c0adc38 100755 Binary files a/packages/validator/fixtures/programs/risk_engine.so and b/packages/validator/fixtures/programs/risk_engine.so differ diff --git a/packages/validator/fixtures/programs/spot_instrument.so b/packages/validator/fixtures/programs/spot_instrument.so index c7a32462b..f47227c03 100755 Binary files a/packages/validator/fixtures/programs/spot_instrument.so and b/packages/validator/fixtures/programs/spot_instrument.so differ diff --git a/packages/validator/fixtures/pubkey-naming.json b/packages/validator/fixtures/pubkey-naming.json new file mode 100644 index 000000000..12a500710 --- /dev/null +++ b/packages/validator/fixtures/pubkey-naming.json @@ -0,0 +1,47 @@ +{ + "7mbGUAWCyC2NRpx9LsGNyAQbcp9VdRunZrjVvFQUYMNY": "account-dao", + "5c1yzmnQg2bL8bdbUeBdgZ2RB5CAcjWN1yz6P1B8ccf8": "account-maker", + "EfotJvuqAdsPx4RFTNsnEABBuAyACNnjEKKR5zyE4HVx": "account-taker", + "4WbVwc5Edfo3oB1n16bVC9qrghYHSNh1qAECbSCyiT95": "hxro-print-trade-provider", + "GizbUy6geL8B6jWGrnkH7jYvExBhpSpEzMyvx9hZfaho": "hxro-print-trade-provider-config", + "FLaFgJ3Qa3bSGxUhiPCF3cgU1XhpTZKaSev7RUMbFYJZ": "mint-btc", + "3kg8xjMx3EWdAuGcm6gqgXFXbgQKk5b88N6AeAo26CbM": "mint-eth", + "3kePJGX9JBSMqqmLMBYZaJh6XksemDQA5EV2D1HR5w9L": "mint-sol", + "85HShAwuaknk3srchNcfmg4SZU9PsNzPvECnaqH62PDa": "mint-usd-collateral", + "9JgYBxL6w11XJ4xtvEicRhXGse6A1akPgZJaKjM1JnZB": "mint-usd-quote", + "HGmSFSRfVAG8RC8Ae4G1JFSHK7Au5GrGskDxncG3JRok": "psyoptions-american-instrument", + "6B7TdBNAF7tWWz5sZbbBZj8jH1ix7QWAchtkvMHveEuW": "psyoptions-european-instrument", + "EMFRxsc7FSavsUVKuwNiywXixYthe2Mo5GUNaUvnvBva": "rfq", + "9WJ5B36cb23UVuTGAw3cF3PdkwYcpRd3or9NB2feXob2": "rfq-base-asset-btc", + "CtUPSK5cXRmsr1wGo5nCjfHQ9Dca6hsg26FBiZcMsTVp": "rfq-base-asset-eth", + "7RMoZT2GLMvT5LiuXL9gSPcHdwEsS9f8Gi116cQ9ydNv": "rfq-base-asset-sol", + "ADSmGasDML6HXpRxACYjAqWz8icFib4hztZ6YF3vNtH6": "rfq-collateral-info-dao", + "48qiMm1RzkdLJ4HT63pwB2LXtUo8Z9idwJouQpeTwhfR": "rfq-collateral-info-maker", + "8k1Pv1RjECRindE1PVzBuoVMUZz8mNFxrGj5oSMFiyiu": "rfq-collateral-info-taker", + "Bc7HGjyAymBhA1xHPZpnGMnaju6jiYThMvvbo8qWpVE8": "rfq-collateral-token-dao", + "Eu5Ckc6jV6MMPtQLkNWMr3g3kd1oTXhfYL5nqTdH8hqy": "rfq-collateral-token-maker", + "4Ebb8C6qYMYa9Cup7fHsWkdU8J5qxXfXoUoPcgAqYJ8c": "rfq-collateral-token-taker", + "CCGguC4YFVLr17tM317mbqvechmgZvH1To5BcKi43GXX": "rfq-mint-info-btc", + "F74ZnvhTmF9JRJ9LCQ6kxfkSUXaLfHy9dxMnavpGWkBT": "rfq-mint-info-eth", + "4foY3PJTrLUt4nPJuuQy7WuRKz6kJXCuLBwxXdmSYgP2": "rfq-mint-info-sol", + "3UV85jwjPmdL71q2kXiPZQbnz8N9CiYbvKadzaNhxX6W": "rfq-mint-info-usd-quote", + "GjDjkE8YnpE4ugQGg2E7qbDnFn1eb6DP9FEWbT22UPxy": "rfq-protocol", + "F3o2hWqv61TavHuZYuStvW2Zd3M1JnoqBmmgGU77LRTr": "risk-engine", + "66TqCm7S1tEjC96TEggh2EpcYdmAppZy3qHLapP3peX": "risk-engine-config", + "4A9M7iojGDPc4n4YDGnTmsYsNKUohG1zM1nrAqVMMmrm": "spot-instrument", + "CBVMytnrNLSMZR4kRBwpp87iNeuexMehJFMTcizW86Yy": "token-account-btc-dao", + "24z1PN6o4swFd1ztLevjSbM6hnLd96wd65BVv3QkeCrU": "token-account-btc-maker", + "EB25yJhPe4X4ZWkDoeTm8HRpKgtqZGWKZAS58ifBkmGV": "token-account-btc-taker", + "4iXPAYibFSh8XgEAbmgbYhTbmRspGMykDzuk14kWwKa1": "token-account-eth-dao", + "AESoo2Gu9betexr8frYw3PueY623PFCCVgETBLejzzDW": "token-account-eth-maker", + "GHhfVCtkmxGLjCkrx9hW3rUSDpMimnxPEqGfMfNypHkZ": "token-account-eth-taker", + "JBPr3RLqLhiDh8wTn2QBz2ucQ3rPbuDYFGUAcDX36u45": "token-account-sol-dao", + "K9SGBfHNkEaZF9jcgWxfvT7ECUfSvpgH5D1rRSdhUPF": "token-account-sol-maker", + "2RY3MWhi5wdeqKKNnwVAMHgdZENePM4EaAzK7T56hrLy": "token-account-sol-taker", + "9WWe769YU4jMWy3CxypQZNmDDnmQQbyx2hPxtJqbLq79": "token-account-usd-collateral-dao", + "4BPzsvRcNt6SGnhLN3Z5y81yuEwnysRsGrJ14tBLjKi6": "token-account-usd-collateral-maker", + "7DTftDbxGPfDi6fA7ooGgEW4ELcmZDfrjXXJHbcKgpbt": "token-account-usd-collateral-taker", + "7t4TQvMCkpJj23t2XVWhcJZu5kPoyMvvTR4dDVPQ8WsA": "token-account-usd-quote-dao", + "G47NrfrvTpdiUc3m9jZn6x98qQYkuD6nYy98tmUMMuvn": "token-account-usd-quote-maker", + "7Q4CtjBBJJwXbuFstgsjpPKcupaRahgoAVPuDy6MjgQF": "token-account-usd-quote-taker" +} \ No newline at end of file diff --git a/packages/validator/helpers.ts b/packages/validator/helpers.ts index ec2ca9d04..7407a2157 100644 --- a/packages/validator/helpers.ts +++ b/packages/validator/helpers.ts @@ -1,13 +1,14 @@ import { spawn, ChildProcessWithoutNullStreams } from 'child_process'; import fs from 'fs'; import path from 'path'; -import { Keypair } from '@solana/web3.js'; +import { Keypair, PublicKey } from '@solana/web3.js'; import * as rfq from '@convergence-rfq/rfq'; import * as riskEngine from '@convergence-rfq/risk-engine'; import * as spotInstrument from '@convergence-rfq/spot-instrument'; import * as psyoptionsEuropeanInstrument from '@convergence-rfq/psyoptions-european-instrument'; import * as psyoptionsAmericanInstrument from '@convergence-rfq/psyoptions-american-instrument'; +import * as hxroPrintTradeProvider from '@convergence-rfq/hxro-print-trade-provider'; export type ChildProccess = ChildProcessWithoutNullStreams; @@ -15,6 +16,7 @@ export const RPC_ENDPOINT = 'http://127.0.0.1:8899'; export const FIXTURES = path.join(__dirname, 'fixtures'); export const DEPS = path.join(__dirname, 'dependencies'); +export const HXRO_DEPS = path.join(DEPS, 'hxro'); const PSYOPTIONS_AMERICAN = 'R2y9ip6mxmWUj4pt54jP2hz2dgvMozy9VTSwMWE7evs'; const PSYOPTIONS_EURO = 'FASQhaZQT53W9eT9wWnPoBFw8xzZDey9TbMmJj6jCQTs'; @@ -22,6 +24,12 @@ const SWITCHBOARD_BTC_ORACLE = '8SXvChNYFhRq4EZuZvnhjrB3jJRQCv4k3P4W6hesH3Ee'; const PYTH_SOL_ORACLE = 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG'; const PYTH_ORACLE = 'FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH'; +const HXRO_DEX = 'FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL'; +const HXRO_AAOB = 'DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b'; +const HXRO_INSTRUMENT = '8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq'; +const HXRO_FEES = '5T9gt3frWPAvu1hxEULbsKrP2WF4ggqSxCMqpJvtWXHV'; +export const HXRO_RISK_ENGINE = 'BVDTB61eHY7UnCb4ueatdaV4rctTzqfLAL6sQDeMNSHA'; + const getBaseArgs = () => [ '--account', SWITCHBOARD_BTC_ORACLE, @@ -36,11 +44,35 @@ const getBaseArgs = () => [ '--bpf-program', PSYOPTIONS_EURO, path.join(DEPS, 'euro_primitive.so'), - '--bpf-program', PYTH_ORACLE, path.join(DEPS, 'pseudo_pyth.so'), + '--bpf-program', + HXRO_DEX, + path.join( + HXRO_DEPS, + 'programs/dex_FUfpR31LmcP1VSbz5zDaM7nxnH55iBHkpwusgrnhaFjL.so' + ), + '--bpf-program', + HXRO_AAOB, + path.join( + HXRO_DEPS, + 'programs/aaob_DchhQ6g8LyRCM5mnao1MAg3g9twfqBbDmUWgpQpFfn1b.so' + ), + '--bpf-program', + HXRO_INSTRUMENT, + path.join( + HXRO_DEPS, + 'programs/instrument_8981bZYszfz1FrFVx7gcUm61RfawMoAHnURuERRJKdkq.so' + ), + '--bpf-program', + HXRO_FEES, + path.join(HXRO_DEPS, 'programs/constant_fees.so'), + '--bpf-program', + HXRO_RISK_ENGINE, + path.join(HXRO_DEPS, 'programs/noop_risk_engine.so'), + '--bpf-program', rfq.PROGRAM_ADDRESS, path.join(FIXTURES, 'programs/rfq.so'), @@ -56,6 +88,15 @@ const getBaseArgs = () => [ '--bpf-program', riskEngine.PROGRAM_ADDRESS, path.join(FIXTURES, 'programs/risk_engine.so'), + '--bpf-program', + hxroPrintTradeProvider.PROGRAM_ADDRESS, + path.join(FIXTURES, 'programs/hxro_print_trade_provider.so'), + + '--account-dir', + path.join(FIXTURES, 'accounts'), + + '--account-dir', + path.join(HXRO_DEPS, 'accounts'), '--ledger', './test-ledger', @@ -96,6 +137,11 @@ export class Ctx { // Pyth pythSOLOracle = getDepAccountPk('sol_30_oracle_pyth'); + + // Hxro + hxroMpg = new PublicKey(getHxroAccountPk('mpg')); + hxroTakerTrg = new PublicKey(getHxroAccountPk('taker-trg')); + hxroMakerTrg = new PublicKey(getHxroAccountPk('maker-trg')); } export const getAccountPk = (user: string): string => { @@ -112,6 +158,13 @@ export const getDepAccountPk = (user: string): string => { return json.pubkey; }; +export const getHxroAccountPk = (name: string): string => { + const f = path.join(HXRO_DEPS, 'accounts', name + '.json'); + const fileContent = fs.readFileSync(f, 'utf-8'); + const json = JSON.parse(fileContent); + return json.pubkey; +}; + export const getKpFile = (user: string): string => { return path.join(FIXTURES, 'keypairs', `${user}.json`); }; @@ -128,7 +181,6 @@ export const getUserKp = (user: string) => { export const spawnValidator = (done = () => {}): ChildProccess => { const args = getBaseArgs(); - args.push('--account-dir', path.join(FIXTURES, 'accounts')); const validator = spawn('solana-test-validator', args); validator.on('exit', process.exit); diff --git a/rollup.config.js b/rollup.config.js index 0db0809f6..f876ad9cb 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -81,7 +81,8 @@ const createConfig = (build, options) => { 'process.env.BROWSER': JSON.stringify(browser), }, }), - ...(bundle ? [json(), nodePolyfills()] : []), + json(), + ...(bundle ? [nodePolyfills()] : []), ...(minified ? [terser()] : []), ], onwarn(warning, rollupWarn) { diff --git a/yarn.lock b/yarn.lock index 4f8acd645..241f72ee4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1027,6 +1027,17 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@bonfida/aaob@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@bonfida/aaob/-/aaob-0.0.3.tgz#9157aa3aab32abc5e78294801317f53481fa8654" + integrity sha512-YLac//38o470VFUOqDnXXIbouJ61cJK6OgylE1sBdm4zvBNsf2/xu2DthhsnLvphIVqY5KLK+VB6iOgtG4olmw== + dependencies: + "@solana/spl-token" "0.1.5" + "@solana/web3.js" "^1.15.0" + bn.js "^5.1.3" + borsh "^0.6.0" + bs58 "4.0.1" + "@bundlr-network/client@^0.8.8": version "0.8.9" resolved "https://registry.yarnpkg.com/@bundlr-network/client/-/client-0.8.9.tgz#58e969a5d80f8d25d212d46bb7a060730a3c1736" @@ -1270,10 +1281,10 @@ bn.js "^5.2.0" debug "^4.3.3" -"@convergence-rfq/psyoptions-american-instrument@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@convergence-rfq/psyoptions-american-instrument/-/psyoptions-american-instrument-2.3.3.tgz#d446b6951e2c032fd0086719b0888f156da87a42" - integrity sha512-tb0fF3lMV85pSGPU3xNDj8o1nzloR0rVFDHpS2yEK9HNUKCnBPNF+gFWwSAfiNme4l//vO/SAXKJodof60OkaA== +"@convergence-rfq/hxro-print-trade-provider@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/hxro-print-trade-provider/-/hxro-print-trade-provider-3.8.0.tgz#fbde20acc78cd67dd7320b319a5b43d31d9a8f2b" + integrity sha512-rTPysSD38HPJp1rOkm1Pu2kjSK4Q9FRYkSRcuNmnZpj9h+goqzHrqVCS7jVOWS7D2lj0DqEXidFl/TSkraTopw== dependencies: "@convergence-rfq/beet" "^0.7.10" "@convergence-rfq/beet-solana" "^0.4.11" @@ -1281,10 +1292,10 @@ "@solana/web3.js" "^1.56.2" bn.js "^5.2.0" -"@convergence-rfq/psyoptions-european-instrument@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@convergence-rfq/psyoptions-european-instrument/-/psyoptions-european-instrument-2.3.3.tgz#72a8a49fc89b5f97887ea4d06c08fc5ec0758320" - integrity sha512-6PpNHZNgkWqXGm7s3KP+Wbk6Y5UijkqBw6M8r/M+xvrqu7++qj/yRWa1CYUz14kOKNYHGj2Kbp7U/Azr6fPt2A== +"@convergence-rfq/psyoptions-american-instrument@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/psyoptions-american-instrument/-/psyoptions-american-instrument-3.8.0.tgz#4f762d39c786ca06a4138df9f03b8cb1d2fef1fa" + integrity sha512-rfyiJb+Am86BUQaeEMGXiNtw7AI13S5jL7OabMd80XpQ0hY6ylnzGyZFNByq4foDrYXPlHo3O6TpBBIbGiJMmQ== dependencies: "@convergence-rfq/beet" "^0.7.10" "@convergence-rfq/beet-solana" "^0.4.11" @@ -1292,10 +1303,10 @@ "@solana/web3.js" "^1.56.2" bn.js "^5.2.0" -"@convergence-rfq/rfq@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@convergence-rfq/rfq/-/rfq-2.3.3.tgz#b8a0f88406250c83d402c1f9fcc9c84fdfe38420" - integrity sha512-r0LZJPJb2YgqfK3hl4jncBw17/bf8T2chpQqjNuaVxMt/itc6e1a7XHGxWjVmMzu9rUKi24WITO5KzJuzsuQVw== +"@convergence-rfq/psyoptions-european-instrument@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/psyoptions-european-instrument/-/psyoptions-european-instrument-3.8.0.tgz#25b097016f57d2fa59264a61ac1a866f5294bc5f" + integrity sha512-AtqrOMFmeBdg4rYZE7ISKdjzTmZczHSrECKmkGud42C5sZkS9+dNI7I7k0UMThDhBGEu9CwbXEWsQXfJw9e+aw== dependencies: "@convergence-rfq/beet" "^0.7.10" "@convergence-rfq/beet-solana" "^0.4.11" @@ -1303,10 +1314,10 @@ "@solana/web3.js" "^1.56.2" bn.js "^5.2.0" -"@convergence-rfq/risk-engine@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@convergence-rfq/risk-engine/-/risk-engine-2.3.3.tgz#0873903853a2e1a81a43629f5c22ea44e138ada5" - integrity sha512-jdEU7yQfreQXhUbkEEKlHW+aSYPdmVWra/efjSN6/3BEjLyjEk5YaSbeMnGdaQ66dfgNL0qSmGk5JNcqMKv1Mg== +"@convergence-rfq/rfq@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/rfq/-/rfq-3.8.0.tgz#545a39766832f5bd1050acecbe93a4fd1ef4d6a1" + integrity sha512-oKaJ0xsHZhxIf2jCPzYE0yDSOqbdZzWqwL5IGVVZkPac6IWsQwfa11PiaSE2Xt5R+gJH1VyKFUranwCE+DQBEg== dependencies: "@convergence-rfq/beet" "^0.7.10" "@convergence-rfq/beet-solana" "^0.4.11" @@ -1314,10 +1325,10 @@ "@solana/web3.js" "^1.56.2" bn.js "^5.2.0" -"@convergence-rfq/spot-instrument@2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@convergence-rfq/spot-instrument/-/spot-instrument-2.3.3.tgz#3ce0ebf81fc5d407496db43fea2fb020a82c6f8c" - integrity sha512-GjmB2dDHgFOGXcZs4Cfn9iJ5iyJa9KBQhgNqAc5RD68o7zecqJRmvvFU8Qm/Z4u70AxUaO2RCU2rJHE0X7mfLQ== +"@convergence-rfq/risk-engine@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/risk-engine/-/risk-engine-3.8.0.tgz#05df6a6bdef2ddbd18ba4d55df1b5329a85b8222" + integrity sha512-b/WimuZR31HP6aW09xnzjlmZc/hZ3mi+7Wxz1OxcUiFUbtfKJbEFzw0+MAMI9lOulk+VFxb4yd7UBP8Y3AJVAw== dependencies: "@convergence-rfq/beet" "^0.7.10" "@convergence-rfq/beet-solana" "^0.4.11" @@ -1325,6 +1336,58 @@ "@solana/web3.js" "^1.56.2" bn.js "^5.2.0" +"@convergence-rfq/spot-instrument@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@convergence-rfq/spot-instrument/-/spot-instrument-3.8.0.tgz#5e1a5f294a667b96ba9fffa2542c9c336765067e" + integrity sha512-+va2znXJQZRMr4WsUPUsrLPXTajSuQBtE61c5IfABbrbCokyYUJy3pSDTNY9HuGjErs+M2TiyTlUSSmgK4B2xQ== + dependencies: + "@convergence-rfq/beet" "^0.7.10" + "@convergence-rfq/beet-solana" "^0.4.11" + "@solana/spl-token" "^0.3.5" + "@solana/web3.js" "^1.56.2" + bn.js "^5.2.0" + +"@coral-xyz/anchor@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.28.0.tgz#8345c3c9186a91f095f704d7b90cd256f7e8b2dc" + integrity sha512-kQ02Hv2ZqxtWP30WN1d4xxT4QqlOXYDxmEd3k/bbneqhV3X5QMO4LAtoUFs7otxyivOgoqam5Il5qx81FuI4vw== + dependencies: + "@coral-xyz/borsh" "^0.28.0" + "@solana/web3.js" "^1.68.0" + base64-js "^1.5.1" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + js-sha256 "^0.9.0" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + +"@coral-xyz/anchor@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.29.0.tgz#bd0be95bedfb30a381c3e676e5926124c310ff12" + integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + "@coral-xyz/borsh@^0.26.0": version "0.26.0" resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.26.0.tgz#d054f64536d824634969e74138f9f7c52bbbc0d5" @@ -1333,6 +1396,22 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@coral-xyz/borsh@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.28.0.tgz#fa368a2f2475bbf6f828f4657f40a52102e02b6d" + integrity sha512-/u1VTzw7XooK7rqeD7JLUSwOyRSesPUk0U37BV9zK0axJc1q0nRbKFGFLYCQ16OtdOJTTwGfGp11Lx9B45bRCQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.29.0.tgz#79f7045df2ef66da8006d47f5399c7190363e71f" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1360,10 +1439,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.56.0": - version "8.56.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" - integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== "@ethereumjs/rlp@^4.0.1": version "4.0.1" @@ -1733,7 +1812,7 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@humanwhocodes/config-array@^0.11.13": +"@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== @@ -1752,6 +1831,23 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@hxronetwork/dexterity-ts@1.6.16": + version "1.6.16" + resolved "https://registry.yarnpkg.com/@hxronetwork/dexterity-ts/-/dexterity-ts-1.6.16.tgz#2fc4c9b78246756838ffbde09165733b1089c7fe" + integrity sha512-g3SQ8MsMztI1t7WolPG5dWtZhsOYDeCSgLojQNtMm2fCyGhENRnrRweKuz4aJTVOgCb/u0NdtOmmnvB5v66cKw== + dependencies: + "@bonfida/aaob" "0.0.3" + "@coral-xyz/anchor" "^0.29.0" + "@solana/spl-token" "^0.2.0" + "@types/react" "^18.0.7" + bn.js "^5.2.0" + borsh "^0.7.0" + buffer "^6.0.3" + isomorphic-ws "^5.0.0" + react "^18.0.0" + typescript "4.7" + ws "^8.9.0" + "@identity.com/solana-gateway-ts@^0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@identity.com/solana-gateway-ts/-/solana-gateway-ts-0.9.0.tgz#23ce316f1cfd3b30e84bde31079de53e81f26c8f" @@ -1975,9 +2071,9 @@ chalk "^4.0.0" "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz#9b18145d26cf33d08576cf4c7665b28554480ed7" + integrity sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw== dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -2007,9 +2103,9 @@ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.22" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" - integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== + version "0.3.23" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz#afc96847f3f07841477f303eed687707a5aacd80" + integrity sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -2067,7 +2163,7 @@ resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== -"@noble/hashes@1.3.3", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.2": +"@noble/hashes@1.3.3", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== @@ -2613,9 +2709,9 @@ integrity sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ== "@smithy/types@^2.9.1": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.9.1.tgz#ed04d4144eed3b8bd26d20fc85aae8d6e357ebb9" - integrity sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw== + version "2.10.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.10.0.tgz#1cc16e3c04d56c49ecb88efa1b7fa9ca3a90d667" + integrity sha512-QYXQmpIebS8/jYXgyJjCanKZbI4Rr8tBVGBAIdDhA35f025TVjJNW69FJ0TGiDqt+lIGo037YIswq2t2Y1AYZQ== dependencies: tslib "^2.5.0" @@ -2684,6 +2780,18 @@ "@solana/options" "2.0.0-experimental.8618508" "@solana/spl-type-length-value" "0.1.0" +"@solana/spl-token@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.1.5.tgz#dcb6cb4bd7acb3c6457500502b6e62c75d18d05b" + integrity sha512-2rlgKbH3lCTIuxwm4A+R2/t+w3Rt2tJLpGH6jefQQUpM6MyxlQWV+P9pB7+lozuWDOJ7A2OyKkUEt/HlxyHFjw== + dependencies: + "@babel/runtime" "^7.10.5" + "@solana/web3.js" "^1.12.0" + bn.js "^5.1.0" + buffer "6.0.3" + buffer-layout "^1.2.0" + dotenv "10.0.0" + "@solana/spl-token@^0.1.6", "@solana/spl-token@^0.1.8": version "0.1.8" resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.1.8.tgz#f06e746341ef8d04165e21fc7f555492a2a0faa6" @@ -2741,7 +2849,7 @@ "@wallet-standard/base" "^1.0.1" "@wallet-standard/features" "^1.0.3" -"@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.28.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.87.6": +"@solana/web3.js@^1.12.0", "@solana/web3.js@^1.15.0", "@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.28.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.87.6": version "1.90.0" resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.90.0.tgz#a0f1364b4235d32a43649b74c52d9fb8bc9436a3" integrity sha512-p0cb/COXb8NNVSMkGMPwqQ6NvObZgUitN80uOedMB+jbYWOKOeJBuPnzhenkIV9RX0krGwyuY1Ltn5O8MGFsEw== @@ -2951,9 +3059,9 @@ form-data "^4.0.0" "@types/node@*": - version "20.11.19" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195" - integrity sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ== + version "20.11.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.20.tgz#f0a2aee575215149a62784210ad88b3a34843659" + integrity sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg== dependencies: undici-types "~5.26.4" @@ -2982,6 +3090,20 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== +"@types/prop-types@*": + version "15.7.11" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" + integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== + +"@types/react@^18.0.7": + version "18.2.60" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.60.tgz#df026eaef1100b6dafe420f36fecb1d209a8cee1" + integrity sha512-dfiPj9+k20jJrLGOu9Nf6eqxm2EyJRrq2NvwOFsfbb7sFExZ9WELPs67UImHj3Ayxg8ruTtKtNnbjaF8olPq0A== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/resolve@1.17.1": version "1.17.1" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" @@ -2989,10 +3111,15 @@ dependencies: "@types/node" "*" +"@types/scheduler@*": + version "0.16.8" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" + integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== + "@types/semver@^7.3.12", "@types/semver@^7.5.0": - version "7.5.7" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.7.tgz#326f5fdda70d13580777bcaa1bc6fa772a5aef0e" - integrity sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg== + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/sinon@^10.0.13": version "10.0.20" @@ -3144,52 +3271,52 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@vue/compiler-core@3.4.19": - version "3.4.19" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.19.tgz#3161b1ede69da00f3ce8155dfab907a3eaa0515e" - integrity sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w== +"@vue/compiler-core@3.4.20": + version "3.4.20" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.20.tgz#1fc69daaff164ef804fe700896952dd2ce2ff082" + integrity sha512-l7M+xUuL8hrGtRLkrf+62d9zucAdgqNBTbJ/NufCOIuJQhauhfyAKH9ra/qUctCXcULwmclGAVpvmxjbBO30qg== dependencies: "@babel/parser" "^7.23.9" - "@vue/shared" "3.4.19" + "@vue/shared" "3.4.20" entities "^4.5.0" estree-walker "^2.0.2" source-map-js "^1.0.2" -"@vue/compiler-dom@3.4.19": - version "3.4.19" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz#2457e57e978f431e3b5fd11fc50a3e92d5816f9a" - integrity sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA== +"@vue/compiler-dom@3.4.20": + version "3.4.20" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.20.tgz#a1fd73e9c940021645679cde77caf7a0a51efaa9" + integrity sha512-/cSBGL79HFBYgDnqCNKErOav3bPde3n0sJwJM2Z09rXlkiowV/2SG1tgDAiWS1CatS4Cvo0o74e1vNeCK1R3RA== dependencies: - "@vue/compiler-core" "3.4.19" - "@vue/shared" "3.4.19" + "@vue/compiler-core" "3.4.20" + "@vue/shared" "3.4.20" "@vue/compiler-sfc@^3.3.4": - version "3.4.19" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.19.tgz#33b238ded6d63e51f6a7048b742626f6007df129" - integrity sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg== + version "3.4.20" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.20.tgz#854ea80a61645f282d4783f744b42fd3fc5bcfd0" + integrity sha512-nPuTZz0yxTPzjyYe+9nQQsFYImcz/57UX8N3jyhl5oIUUs2jqqAMaULsAlJwve3qNYfjQzq0bwy3pqJrN9ecZw== dependencies: "@babel/parser" "^7.23.9" - "@vue/compiler-core" "3.4.19" - "@vue/compiler-dom" "3.4.19" - "@vue/compiler-ssr" "3.4.19" - "@vue/shared" "3.4.19" + "@vue/compiler-core" "3.4.20" + "@vue/compiler-dom" "3.4.20" + "@vue/compiler-ssr" "3.4.20" + "@vue/shared" "3.4.20" estree-walker "^2.0.2" - magic-string "^0.30.6" - postcss "^8.4.33" + magic-string "^0.30.7" + postcss "^8.4.35" source-map-js "^1.0.2" -"@vue/compiler-ssr@3.4.19": - version "3.4.19" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.19.tgz#1f8ee06005ebbaa354f8783fad84e9f7ea4a69c2" - integrity sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw== +"@vue/compiler-ssr@3.4.20": + version "3.4.20" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.20.tgz#3602bd176dc82c2aff3261761d04df3023ecb938" + integrity sha512-b3gFQPiHLvI12C56otzBPpQhZ5kgkJ5RMv/zpLjLC2BIFwX5GktDqYQ7xg0Q2grP6uFI8al3beVKvAVxFtXmIg== dependencies: - "@vue/compiler-dom" "3.4.19" - "@vue/shared" "3.4.19" + "@vue/compiler-dom" "3.4.20" + "@vue/shared" "3.4.20" -"@vue/shared@3.4.19": - version "3.4.19" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.19.tgz#28105147811bcf1e6612bf1c9ab0c6d91ada019c" - integrity sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw== +"@vue/shared@3.4.20": + version "3.4.20" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.20.tgz#13b7d1e2a3752bbc032b38f53dba5c2f430eea7e" + integrity sha512-KTEngal0aiUvNJ6I1Chk5Ew5XqChsFsxP4GKAYXWb99zKJWjNU72p2FWEOmZWHxHcqtniOJsgnpd3zizdpfEag== "@wallet-standard/base@^1.0.1": version "1.0.1" @@ -3584,10 +3711,12 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" - integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== +available-typed-arrays@^1.0.6, available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" "avsc@https://github.com/Irys-xyz/avsc#csp-fixes": version "5.4.7" @@ -3839,7 +3968,7 @@ bn.js@^4.0.0, bn.js@^4.11.9: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bn.js@^5.0.0, bn.js@^5.1.0, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -3921,7 +4050,7 @@ browserslist@^4.22.2, browserslist@^4.22.3: node-releases "^2.0.14" update-browserslist-db "^1.0.13" -bs58@^4.0.0, bs58@^4.0.1: +bs58@4.0.1, bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== @@ -4036,9 +4165,9 @@ camelcase@^6.0.0, camelcase@^6.2.0, camelcase@^6.3.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001587" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz#a0bce920155fa56a1885a69c74e1163fc34b4881" - integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== + version "1.0.30001591" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz#16745e50263edc9f395895a7cd468b9f3767cf33" + integrity sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ== capability@^0.2.5: version "0.2.5" @@ -4409,6 +4538,11 @@ crypto-js@^3.1.9-1: resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + csv-generate@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-3.4.3.tgz#bc42d943b45aea52afa896874291da4b9108ffff" @@ -4520,7 +4654,7 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-data-property@^1.0.1, define-data-property@^1.1.2: +define-data-property@^1.0.1, define-data-property@^1.1.2, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -4689,9 +4823,9 @@ ejs@^3.1.7: jake "^10.8.5" electron-to-chromium@^1.4.668: - version "1.4.672" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.672.tgz#f8ce803b43898b7e91dcfcf70d6fd656b11a645d" - integrity sha512-YYCy+goe3UqZqa3MOQCI5Mx/6HdBLzXL/mkbGCEWL3sP3Z1BP9zqAzeD3YEmLZlespYGFtyM8tRp5i2vfaUGCA== + version "1.4.682" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.682.tgz#27577b88ccccc810e09b05093345cf1830f1bd65" + integrity sha512-oCglfs8yYKs9RQjJFOHonSnhikPK3y+0SvSYc/YpYJV//6rqc0/hbwd0c7vgK4vrl6y2gJAwjkhkSGWK+z4KRA== elliptic@6.5.4, elliptic@^6.5.4: version "6.5.4" @@ -4834,13 +4968,13 @@ es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-set-tostringtag@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" @@ -4910,9 +5044,9 @@ eslint-import-resolver-node@^0.3.9: resolve "^1.22.4" eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + version "2.8.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" + integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== dependencies: debug "^3.2.7" @@ -4924,9 +5058,9 @@ eslint-plugin-cypress@^2.12.1: globals "^13.20.0" eslint-plugin-eslint-plugin@^5.0.6: - version "5.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-5.3.0.tgz#7bb3004c907d1421f134a985fe5d0f6b4a7eee63" - integrity sha512-mRMH3WwewpZjbdOFbE0Vr0EJ4Q6oIXLRGkFQyRM+HWhpNIhYWy/3solQ+blVS8noSkD2/jq7iW3Ke3N0viUJ/w== + version "5.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-5.4.0.tgz#61782d2252d400451b494a3fb2db2d9c04e34745" + integrity sha512-79izqWfmWmvGEWse5rZQlrcqPp34g07ZE1AyzbB8qnS8dnxJvc4vltGT6xuYIPvpQoQECzW5bGeD4BvOxUYvBA== dependencies: eslint-utils "^3.0.0" estraverse "^5.3.0" @@ -4977,9 +5111,9 @@ eslint-plugin-prettier@^4.2.1: prettier-linter-helpers "^1.0.0" eslint-plugin-sort-class-members@^1.15.2: - version "1.19.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-sort-class-members/-/eslint-plugin-sort-class-members-1.19.0.tgz#9ad7a674c4cb477fceaddb8162515372d381c733" - integrity sha512-YayvASA1bavdPeRU9FMPnale2+Oi3aMcHGVC5EUm9b671oxm7ahvR+q8BfsU2aV+KAFezNfu47VPgdZK6gwYPw== + version "1.20.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-sort-class-members/-/eslint-plugin-sort-class-members-1.20.0.tgz#88ea3d53b2ffb319dba1049c28e20797685a0b9e" + integrity sha512-xNaik4GQ/pRwd1soIVI28HEXZbrWoLR5krau2+E8YcHj7N09UviPg5mYhf/rELG29bIFJdXDOFJazN90+luMOw== eslint-scope@^5.1.1: version "5.1.1" @@ -5015,15 +5149,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.23.0: - version "8.56.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" - integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.56.0" - "@humanwhocodes/config-array" "^0.11.13" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" "@ungap/structured-clone" "^1.2.0" @@ -5480,9 +5614,9 @@ flat@^5.0.2: integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.14.0, follow-redirects@^1.14.7, follow-redirects@^1.14.9, follow-redirects@^1.15.4: version "1.15.5" @@ -5803,17 +5937,17 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1, has-property-d dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.1, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -6148,9 +6282,9 @@ is-module@^1.0.0: integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -6195,11 +6329,11 @@ is-regex@^1.1.4: has-tostringtag "^1.0.0" is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" @@ -6232,7 +6366,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.13, is-typed-array@^1.1.9: +is-typed-array@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== @@ -6283,6 +6417,11 @@ isomorphic-ws@^4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" @@ -6347,9 +6486,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.0.2, istanbul-reports@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -6785,9 +6924,9 @@ jest-worker@^28.1.1, jest-worker@^28.1.3: supports-color "^8.0.0" joi@^17.7.0: - version "17.12.1" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.1.tgz#3347ecf4cd3301962d42191c021b165eef1f395b" - integrity sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ== + version "17.12.2" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.2.tgz#283a664dabb80c7e52943c557aab82faea09f521" + integrity sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw== dependencies: "@hapi/hoek" "^9.3.0" "@hapi/topo" "^5.1.0" @@ -6810,7 +6949,7 @@ js-sha512@^0.8.0: resolved "https://registry.yarnpkg.com/js-sha512/-/js-sha512-0.8.0.tgz#dd22db8d02756faccf19f218e3ed61ec8249f7d4" integrity sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ== -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -7093,6 +7232,13 @@ log-update@^5.0.1: strip-ansi "^7.0.1" wrap-ansi "^8.0.1" +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -7134,7 +7280,7 @@ magic-string@^0.25.7: dependencies: sourcemap-codec "^1.4.8" -magic-string@^0.30.6: +magic-string@^0.30.7: version "0.30.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.7.tgz#0cecd0527d473298679da95a2d7aeb8c64048505" integrity sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA== @@ -7576,9 +7722,9 @@ npm-run-path@^4.0.1: path-key "^3.0.0" npm-run-path@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" - integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" @@ -8064,7 +8210,12 @@ plimit-lit@^1.2.6: dependencies: queue-lit "^1.5.1" -postcss@^8.4.33: +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +postcss@^8.4.35: version "8.4.35" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== @@ -8074,9 +8225,9 @@ postcss@^8.4.33: source-map-js "^1.0.2" preferred-pm@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/preferred-pm/-/preferred-pm-3.1.2.tgz#aedb70550734a574dffcbf2ce82642bd1753bdd6" - integrity sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q== + version "3.1.3" + resolved "https://registry.yarnpkg.com/preferred-pm/-/preferred-pm-3.1.3.tgz#4125ea5154603136c3b6444e5f5c94ecf90e4916" + integrity sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w== dependencies: find-up "^5.0.0" find-yarn-workspace-root2 "1.2.16" @@ -8185,6 +8336,13 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -8575,13 +8733,14 @@ set-function-length@^1.2.1: has-property-descriptors "^1.0.1" set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - define-data-property "^1.0.1" + define-data-property "^1.1.4" + es-errors "^1.3.0" functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" setprototypeof@1.2.0: version "1.2.0" @@ -9055,9 +9214,9 @@ terminal-link@^2.0.0: supports-hyperlinks "^2.0.0" terser@^5.0.0: - version "5.27.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.27.1.tgz#b0092975ea1b379d166088a1a57e32f0839d84a2" - integrity sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug== + version "5.28.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.28.1.tgz#bf00f7537fd3a798c352c2d67d67d65c915d1b28" + integrity sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -9333,43 +9492,48 @@ type-fest@^1.0.2: integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== typed-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz#0608ffe6bca71bf15a45bff0ca2604107a1325f5" - integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.6" + call-bind "^1.0.7" es-errors "^1.3.0" is-typed-array "^1.1.13" typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + version "1.0.5" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.5.tgz#57d44da160296d8663fd63180a1802ebf25905d5" + integrity sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typedarray-to-buffer@^3.1.5: version "3.1.5" @@ -9388,6 +9552,11 @@ typedoc@^0.23.0: minimatch "^7.1.3" shiki "^0.14.1" +typescript@4.7: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + typescript@^4.5.4: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -9729,7 +9898,7 @@ ws@^7.4.5: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.5.0: +ws@^8.5.0, ws@^8.9.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==