diff --git a/apps/recovery-relay/lib/defaultRPCs.ts b/apps/recovery-relay/lib/defaultRPCs.ts index f7fef467..aa211042 100644 --- a/apps/recovery-relay/lib/defaultRPCs.ts +++ b/apps/recovery-relay/lib/defaultRPCs.ts @@ -156,4 +156,16 @@ export const defaultRPCs: Record< enabled: true, allowedEmptyValue: false, }, + TON_TEST: { + url: 'https://testnet.toncenter.com/api/v2/jsonRPC', + name: 'The Open Network - Testnet', + enabled: true, + allowedEmptyValue: false, + }, + TON: { + url: 'https://toncenter.com/api/v2/jsonRPC', + name: 'The Open Network', + enabled: true, + allowedEmptyValue: false, + }, }; diff --git a/apps/recovery-relay/lib/wallets/TON/index.ts b/apps/recovery-relay/lib/wallets/TON/index.ts new file mode 100644 index 00000000..4372429e --- /dev/null +++ b/apps/recovery-relay/lib/wallets/TON/index.ts @@ -0,0 +1,139 @@ +import { Ton as BaseTon } from '@fireblocks/wallet-derivation'; +import { TonClient, WalletContractV4 } from '@ton/ton'; +import { beginCell, Cell, fromNano } from '@ton/core'; +import { AccountData } from '../types'; +import { defaultTonWalletV4R2code } from './tonParams'; +import axios from 'axios'; +import { LateInitConnectedWallet } from '../LateInitConnectedWallet'; + +export class Ton extends BaseTon implements LateInitConnectedWallet { + public memo: string | undefined; + + public updateDataEndpoint(memo?: string): void { + this.memo = memo; + } + + public getLateInitLabel(): string { + throw new Error('Method not implemented.'); + } + + public rpcURL: string | undefined; + + public setRPCUrl(url: string): void { + this.rpcURL = url; + } + + private client: TonClient | undefined; + + private init() { + this.client = new TonClient({ + endpoint: this.rpcURL!, + }); + } + + private tonWallet = WalletContractV4.create({ publicKey: Buffer.from(this.publicKey.replace('0x', ''), 'hex'), workchain: 0 }); + + public async getBalance(): Promise { + if (this.client) { + await new Promise((resolve) => setTimeout(resolve, 2000)); + const contract = this.client.open(this.tonWallet); + return Number(fromNano(await contract.getBalance())); + } else { + this.relayLogger.error('TON: Client failed to initialize'); + throw new Error('TON: Client failed to initialize'); + } + } + + public async broadcastTx(tx: string): Promise { + try { + // init the TonClient + this.init(); + + // parse the tx back to Ton Cell + const body = Cell.fromBoc(Buffer.from(tx, 'base64'))[0]; + const pubKey = Buffer.from(this.publicKey.replace('0x', ''), 'hex'); + const externalMessage = beginCell().storeUint(0b10, 2).storeUint(0, 2).storeAddress(this.tonWallet.address).storeCoins(0); + const seqno = await this.getSeqno(); + if (seqno === 0) { + // for the fist transaction we initialize a state init struct which consists of init struct and code + externalMessage + .storeBit(1) // We have State Init + .storeBit(1) // We store State Init as a reference + .storeRef(this.createStateInit(pubKey)); // Store State Init as a reference + } else { + externalMessage.storeBit(0); // We don't have state init + } + const finalExternalMessage = externalMessage.storeBit(1).storeRef(body).endCell(); + + if (this.client) { + // broadcast Tx and calc TxHash + await new Promise((resolve) => setTimeout(resolve, 2000)); + await this.client.sendFile(finalExternalMessage.toBoc()); + const txHash = finalExternalMessage.hash().toString('hex'); + this.relayLogger.debug(`TON: Tx broadcasted: ${txHash}`); + return txHash; + } else { + throw new Error('TON: Client failed to initialize'); + } + } catch (e) { + this.relayLogger.error(`TON: Error broadcasting tx: ${e}`); + if (axios.isAxiosError(e)) { + this.relayLogger.error(`Axios error: ${e.message}\n${e.response?.data}`); + } + throw e; + } + } + + public async prepare(): Promise { + // init the TonClient + this.init(); + // get the balance, returned in nanoTon + const balance = await this.getBalance(); + + // fee for regular tx is hardcoded to 0.02 TON + const feeRate = 0.02; + await new Promise((resolve) => setTimeout(resolve, 2000)); + + // get seqno of the wallet, set it as exrtaParams + const seqno = await this.getSeqno(); + const extraParams = new Map(); + extraParams.set('seqno', seqno); + + const preperedData = { + balance, + memo: this.memo, + feeRate, + extraParams, + insufficientBalance: balance < 0.005, + } as AccountData; + + return preperedData; + } + private async getSeqno() { + await new Promise((resolve) => setTimeout(resolve, 2000)); + return await this.client!.open(this.tonWallet).getSeqno(); + } + + private createStateInit(pubKey: Buffer) { + // the initial data cell our contract will hold. Wallet V4 has an extra value for plugins in the end + const dataCell = beginCell() + .storeUint(0, 32) // Seqno 0 for the first tx + .storeUint(698983191, 32) // Subwallet ID -> https://docs.ton.org/v3/guidelines/smart-contracts/howto/wallet#subwallet-ids + .storeBuffer(pubKey) // Public Key + .storeBit(0) // only for Wallet V4 + .endCell(); + + // we take a boiler place already made WalletV4R2 code + const codeCell = Cell.fromBoc(Buffer.from(defaultTonWalletV4R2code, 'base64'))[0]; + const stateInit = beginCell() + .storeBit(0) // No split_depth + .storeBit(0) // No special + .storeBit(1) // We have code + .storeRef(codeCell) + .storeBit(1) // We have data + .storeRef(dataCell) + .storeBit(0) // No library + .endCell(); + return stateInit; + } +} diff --git a/apps/recovery-relay/lib/wallets/TON/tonParams.ts b/apps/recovery-relay/lib/wallets/TON/tonParams.ts new file mode 100644 index 00000000..320b6689 --- /dev/null +++ b/apps/recovery-relay/lib/wallets/TON/tonParams.ts @@ -0,0 +1,2 @@ +export const defaultTonWalletV4R2code: string = + 'te6ccgECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVA=='; diff --git a/apps/recovery-relay/lib/wallets/index.ts b/apps/recovery-relay/lib/wallets/index.ts index e20408d7..4c109e90 100644 --- a/apps/recovery-relay/lib/wallets/index.ts +++ b/apps/recovery-relay/lib/wallets/index.ts @@ -36,6 +36,7 @@ import { Tezos } from './XTZ'; import { Algorand } from './ALGO'; import { Celestia } from './CELESTIA'; import { CoreDAO } from './EVM/CORE_COREDAO'; +import { Ton } from './TON'; export { ConnectedWallet } from './ConnectedWallet'; export const WalletClasses = { @@ -118,6 +119,8 @@ export const WalletClasses = { HBAR_TEST: Hedera, CELESTIA: Celestia, CELESTIA_TEST: Celestia, + TON: Ton, + TON_TEST: Ton, } as const; type WalletClass = (typeof WalletClasses)[keyof typeof WalletClasses]; diff --git a/apps/recovery-relay/package.json b/apps/recovery-relay/package.json index f7232ef3..c752aea6 100644 --- a/apps/recovery-relay/package.json +++ b/apps/recovery-relay/package.json @@ -36,6 +36,9 @@ "@taquito/signer": "^16.2.0", "@taquito/taquito": "^16.2.0", "@terra-money/terra.js": "^3.1.10", + "@ton/core": "^0.59.0", + "@ton/crypto": "^3.3.0", + "@ton/ton": "^15.1.0", "algosdk": "2.5.0", "axios": "^1.4.0", "base58": "^2.0.1", @@ -82,4 +85,4 @@ "eslint-config-next": "^13.4.9", "typescript": "^5.1.6" } -} \ No newline at end of file +} diff --git a/apps/recovery-utility/renderer/lib/wallets/TON/index.ts b/apps/recovery-utility/renderer/lib/wallets/TON/index.ts new file mode 100644 index 00000000..3608fa2a --- /dev/null +++ b/apps/recovery-utility/renderer/lib/wallets/TON/index.ts @@ -0,0 +1,52 @@ +import { Ton as BaseTon, Input } from '@fireblocks/wallet-derivation'; +import { SigningWallet } from '../SigningWallet'; +import { Address, beginCell, Cell, toNano } from '@ton/core'; +import { GenerateTxInput, TxPayload } from '../types'; + +export class Ton extends BaseTon implements SigningWallet { + constructor(input: Input) { + super(input); + } + + public async generateTx({ to, amount, feeRate, memo, extraParams }: GenerateTxInput): Promise { + // calculate the amount to withdraw + const fee = BigInt(toNano(feeRate!)); // feeRate as BigInt in nano + const amountToWithdraw = BigInt(toNano(amount)) - fee; // amount is the wallet balance + let internalMessageMemo = undefined; + if (memo) { + internalMessageMemo = beginCell().storeUint(0, 32).storeStringTail(memo).endCell(); + } + // create the tx payload + let internalMessage = beginCell() + .storeUint(0x10, 6) // 0x10 is no bounce + .storeAddress(Address.parse(to)) // Store the recipient address + .storeCoins(amountToWithdraw); // Store the amount within the payload + + if (internalMessageMemo) { + internalMessage + .storeUint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1) // store memo as reference + .storeRef(internalMessageMemo) + .endCell(); + } else { + internalMessage.storeUint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1).endCell(); // no memo added + } + + let toSign = beginCell() + .storeUint(698983191, 32) // sub wallet_id + .storeUint(Math.floor(Date.now() / 1e3) + 600, 32) // Transaction expiration time, +600 = 10 minute + .storeUint(extraParams?.get('seqno'), 32) // store seqno + .storeUint(0, 8) + .storeUint(128, 8) // store SendMode as CARRY_ALL_REMAINING_BALANCE + .storeRef(internalMessage) // store our internalMessage as a reference + .endCell(); + + const signMessage = toSign.toBoc().toString('base64'); + const signData = toSign.hash(); + + const signature = Buffer.from(await this.sign(Uint8Array.from(signData))).toString('base64'); + const unsignedTx = Cell.fromBase64(signMessage).asBuilder(); + + const body = beginCell().storeBuffer(Buffer.from(signature, 'base64')).storeBuilder(unsignedTx).endCell(); + return { tx: body.toBoc().toString('base64') }; + } +} diff --git a/apps/recovery-utility/renderer/lib/wallets/index.ts b/apps/recovery-utility/renderer/lib/wallets/index.ts index 3defb89c..59a5a3e1 100644 --- a/apps/recovery-utility/renderer/lib/wallets/index.ts +++ b/apps/recovery-utility/renderer/lib/wallets/index.ts @@ -20,6 +20,7 @@ import { Hedera } from './HBAR'; import { Algorand } from './ALGO'; import { Bitcoin, BitcoinSV, LiteCoin, Dash, ZCash, Doge } from './BTC'; import { Celestia } from './CELESTIA'; +import { Ton } from './TON'; const fillEVMs = () => { const evms = Object.keys(assets).reduce( @@ -95,6 +96,8 @@ export const WalletClasses = { XEM_TEST: NEM, HBAR: Hedera, HBAR_TEST: Hedera, + TON: Ton, + TON_TEST: Ton, ...fillEVMs(), } as const; diff --git a/packages/asset-config/config/patches.ts b/packages/asset-config/config/patches.ts index d6f1e6f1..2a4c4252 100644 --- a/packages/asset-config/config/patches.ts +++ b/packages/asset-config/config/patches.ts @@ -337,4 +337,34 @@ export const nativeAssetPatches: NativeAssetPatches = { memo: false, getExplorerUrl: getStandardExplorer('explorer.testnet.z.cash'), }, + TON: { + derive: true, + transfer: true, + utxo: false, + segwit: false, + minBalance: true, + memo: true, + getExplorerUrl: (type) => (value) => { + if (type === 'tx') { + return `https://tonviewer.com/transaction/${value}`; + } + + return `https://tonviewer.com/${value}`; + }, + }, + TON_TEST: { + derive: true, + transfer: true, + utxo: false, + segwit: false, + minBalance: true, + memo: true, + getExplorerUrl: (type) => (value) => { + if (type === 'tx') { + return `https://testnet.tonviewer.com/transaction/${value}`; + } + + return `https://testnet.tonviewer.com/${value}`; + }, + }, }; diff --git a/packages/e2e-tests/tests.ts b/packages/e2e-tests/tests.ts index e82e84dc..30afd326 100644 --- a/packages/e2e-tests/tests.ts +++ b/packages/e2e-tests/tests.ts @@ -41,6 +41,7 @@ const nativeTestnetAssets: AssetTestConfig[] = [ // { assetId: 'XRP_TEST' }, // { assetId: 'XTZ_TEST' }, // { assetId: 'ZEC_TEST' }, + // { assetId: 'TON_TEST' }, ]; const nativeMainnetAssets = [ @@ -98,6 +99,7 @@ const nativeMainnetAssets = [ // { assetId: 'XRP' }, // { assetId: 'XTZ' }, // { assetId: 'ZEC' }, + // { assetId: 'TON' }, ]; export const testAssets: AssetTestConfig[] = [...nativeTestnetAssets, ...nativeMainnetAssets]; diff --git a/packages/shared/lib/validateAddress.ts b/packages/shared/lib/validateAddress.ts index e52e30a9..fb74d847 100644 --- a/packages/shared/lib/validateAddress.ts +++ b/packages/shared/lib/validateAddress.ts @@ -3,6 +3,7 @@ import { bech32 } from 'bech32'; import { isTestnetAsset } from '@fireblocks/asset-config'; import { getLogger } from './getLogger'; import { LOGGER_NAME_SHARED } from '../constants'; +import { Address } from '@ton/ton'; const logger = getLogger(LOGGER_NAME_SHARED); @@ -101,6 +102,9 @@ export class AddressValidator { return this.validateCOSMOS(address); case 'TERRA': return this.validateTERRA(address); + case 'TON': + case 'TON_TEST': + return this.validateTON(address); default: logger.error(`Unsupported networkProtocol for address validation ${validatorReference}`); throw new Error(`Unsupported networkProtocol for address validation ${validatorReference}`); @@ -150,4 +154,13 @@ export class AddressValidator { private validateTERRA(address: string): boolean { return this.validateCosmosBased('terra')(address); } + + private validateTON(address: string): boolean { + try { + Address.parse(address); + return true; + } catch (error) { + return false; + } + } } diff --git a/packages/wallet-derivation/package.json b/packages/wallet-derivation/package.json index 7b2f60c4..a9f522ba 100644 --- a/packages/wallet-derivation/package.json +++ b/packages/wallet-derivation/package.json @@ -21,6 +21,7 @@ "@solana/web3.js": "^1.78.0", "@substrate/txwrapper-polkadot": "6.0.1", "@terra-money/terra.js": "^3.1.10", + "@ton/ton": "^15.1.0", "@types/bech32": "^1.1.4", "@types/bitcore-lib-cash": "^8.23.5", "@types/blake2b": "^2.1.0", @@ -53,4 +54,4 @@ "ts-jest": "^29.1.1", "ts-node": "^10.9.1" } -} \ No newline at end of file +} diff --git a/packages/wallet-derivation/wallets/EdDSAWallet.ts b/packages/wallet-derivation/wallets/EdDSAWallet.ts index f81d46bb..cea8d2e6 100644 --- a/packages/wallet-derivation/wallets/EdDSAWallet.ts +++ b/packages/wallet-derivation/wallets/EdDSAWallet.ts @@ -141,7 +141,7 @@ export abstract class EdDSAWallet extends BaseWallet { const privateKeyInt = hexToNumber(this.privateKey.slice(2)); const privateKeyBytes = numberToBytesLE(privateKeyInt, 32); - const messagesBytes = typeof message === 'string' ? Buffer.from(message) : message; + const messagesBytes = typeof message === 'string' ? Buffer.from(message, 'hex') : message; const messageBytes = concatBytes(messagesBytes); const seed = randomBytes(); diff --git a/packages/wallet-derivation/wallets/chains/TON.ts b/packages/wallet-derivation/wallets/chains/TON.ts new file mode 100644 index 00000000..086c1451 --- /dev/null +++ b/packages/wallet-derivation/wallets/chains/TON.ts @@ -0,0 +1,19 @@ +import { Input } from '../../types'; +import { EdDSAWallet } from '../EdDSAWallet'; +import { WalletContractV4 } from '@ton/ton'; + +export class Ton extends EdDSAWallet { + constructor(input: Input) { + super(input, 607); + } + + protected getAddress() { + return WalletContractV4.create({ + publicKey: Buffer.from(this.publicKey.replace('0x', ''), 'hex'), + workchain: 0, + }).address.toString({ + bounceable: false, + testOnly: this.isTestnet, + }); + } +} diff --git a/packages/wallet-derivation/wallets/chains/index.ts b/packages/wallet-derivation/wallets/chains/index.ts index 9bc57c63..af267037 100644 --- a/packages/wallet-derivation/wallets/chains/index.ts +++ b/packages/wallet-derivation/wallets/chains/index.ts @@ -25,6 +25,7 @@ import { Tezos } from './XTZ'; import { ZCash } from './ZEC'; import { Hedera } from './HBAR'; import { Celestia } from './TIA'; +import { Ton } from './TON'; export const getWallet = (assetId: string) => { const asset = assets[assetId]; @@ -71,6 +72,9 @@ export const getWallet = (assetId: string) => { case 'HBAR': case 'HBAR_TEST': return Hedera; + case 'TON': + case 'TON_TEST': + return Ton; // ECDSA case 'ATOM_COS': @@ -145,4 +149,5 @@ export { NEM, Hedera, Celestia, + Ton, }; diff --git a/yarn.lock b/yarn.lock index 3e649315..261e7a3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3254,7 +3254,7 @@ rxjs "^7.8.1" tslib "^2.5.3" -"@polkadot/keyring@12.3.2", "@polkadot/keyring@^12.2.1", "@polkadot/keyring@^12.3.1": +"@polkadot/keyring@^12.2.1", "@polkadot/keyring@^12.3.1": version "12.3.2" resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-12.3.2.tgz#112a0c28816a1f47edad6260dc94222c29465a54" integrity sha512-NTdtDeI0DP9l/45hXynNABeP5VB8piw5YR+CbUxK2e36xpJWVXwbcOepzslg5ghE9rs8UKJb30Z/HqTU4sBY0Q== @@ -3440,7 +3440,7 @@ "@polkadot/wasm-util" "7.2.1" tslib "^2.5.0" -"@polkadot/wasm-crypto@7.2.1", "@polkadot/wasm-crypto@^7.2.1": +"@polkadot/wasm-crypto@^7.2.1": version "7.2.1" resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-7.2.1.tgz#db671dcb73f1646dc13478b5ffc3be18c64babe1" integrity sha512-SA2+33S9TAwGhniKgztVN6pxUKpGfN4Tre/eUZGUfpgRkT92wIUT2GpGWQE+fCCqGQgADrNiBcwt6XwdPqMQ4Q== @@ -3467,7 +3467,7 @@ "@polkadot/x-global" "12.3.2" tslib "^2.5.3" -"@polkadot/x-fetch@12.3.2", "@polkadot/x-fetch@^12.3.1": +"@polkadot/x-fetch@^12.3.1": version "12.3.2" resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-12.3.2.tgz#7e8d2113268e792dd5d1b259ef13839c6aa77996" integrity sha512-3IEuZ5S+RI/t33NsdPLIIa5COfDCfpUW2sbaByEczn75aD1jLqJZSEDwiBniJ2osyNd4uUxBf6e5jw7LAZeZJg== @@ -3507,7 +3507,7 @@ "@polkadot/x-global" "12.3.2" tslib "^2.5.3" -"@polkadot/x-ws@12.3.2", "@polkadot/x-ws@^12.3.1": +"@polkadot/x-ws@^12.3.1": version "12.3.2" resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-12.3.2.tgz#422559dfbdaac4c965d5e1b406b6cc4529214f94" integrity sha512-yM9Z64pLNlHpJE43+Xtr+iUXmYpFFY5u5hrke2PJt13O48H8f9Vb9cRaIh94appLyICoS0aekGhDkGH+MCspBA== @@ -4052,6 +4052,40 @@ long "^4.0.0" protobufjs "~6.11.2" +"@ton/core@^0.59.0": + version "0.59.0" + resolved "https://registry.yarnpkg.com/@ton/core/-/core-0.59.0.tgz#58da9fcaa58e5a0c705b63baf1e86cab6e196689" + integrity sha512-LSIkGst7BoY7fMWshejzcH0UJnoW21JGlRrW0ch+6A7Xb/7EuekxgdKym7fHxcry6OIf6FoeFg97lJ960N/Ghg== + dependencies: + symbol.inspect "1.0.1" + +"@ton/crypto-primitives@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@ton/crypto-primitives/-/crypto-primitives-2.1.0.tgz#8c9277c250b59aae3c819e0d6bd61e44d998e9ca" + integrity sha512-PQesoyPgqyI6vzYtCXw4/ZzevePc4VGcJtFwf08v10OevVJHVfW238KBdpj1kEDQkxWLeuNHEpTECNFKnP6tow== + dependencies: + jssha "3.2.0" + +"@ton/crypto@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@ton/crypto/-/crypto-3.3.0.tgz#019103df6540fbc1d8102979b4587bc85ff9779e" + integrity sha512-/A6CYGgA/H36OZ9BbTaGerKtzWp50rg67ZCH2oIjV1NcrBaCK9Z343M+CxedvM7Haf3f/Ee9EhxyeTp0GKMUpA== + dependencies: + "@ton/crypto-primitives" "2.1.0" + jssha "3.2.0" + tweetnacl "1.0.3" + +"@ton/ton@^15.1.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@ton/ton/-/ton-15.1.0.tgz#a760b1492dd3e5896238b7154f7377f4e51fa086" + integrity sha512-almetcfTu7jLjcNcEEPB7wAc8yl90ES1M//sOr1QE+kv7RbmEvMkaPSc7kFxzs10qrjIPKxlodBJlMSWP5LuVQ== + dependencies: + axios "^1.6.7" + dataloader "^2.0.0" + symbol.inspect "1.0.1" + teslabot "^1.3.0" + zod "^3.21.4" + "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -5423,6 +5457,15 @@ axios@^1.4.0, axios@^1.6.0, axios@^1.6.1, axios@^1.6.4: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^1.6.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" @@ -6827,6 +6870,11 @@ data-uri-to-buffer@^4.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== +dataloader@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.2.2.tgz#216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0" + integrity sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g== + date-fns@^2.30.0: version "2.30.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" @@ -8187,6 +8235,11 @@ follow-redirects@^1.14.7, follow-redirects@^1.14.8, follow-redirects@^1.14.9, fo resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -9991,6 +10044,11 @@ jss@10.10.0, jss@^10.10.0: is-in-browser "^1.1.3" tiny-warning "^1.0.2" +jssha@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jssha/-/jssha-3.2.0.tgz#88ec50b866dd1411deaddbe6b3e3692e4c710f16" + integrity sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q== + jssha@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/jssha/-/jssha-2.4.2.tgz#d950b095634928bd6b2bda1d42da9a3a762d65e9" @@ -12950,6 +13008,11 @@ symbol-observable@^4.0.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== +symbol.inspect@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol.inspect/-/symbol.inspect-1.0.1.tgz#e13125b8038c4996eb0dfa1567332ad4dcd0763f" + integrity sha512-YQSL4duoHmLhsTD1Pw8RW6TZ5MaTX5rXJnqacJottr2P2LZBF/Yvrc3ku4NUpMOm8aM0KOCqM+UAkMA5HWQCzQ== + tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -13032,6 +13095,11 @@ terser@^5.16.8, terser@^5.26.0, terser@^5.3.2: commander "^2.20.0" source-map-support "~0.5.20" +teslabot@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/teslabot/-/teslabot-1.5.0.tgz#70f544516699ca5f696d8ae94f3d12cd495d5cd6" + integrity sha512-e2MmELhCgrgZEGo7PQu/6bmYG36IDH+YrBI1iGm6jovXkeDIGa3pZ2WSqRjzkuw2vt1EqfkZoV5GpXgqL8QJVg== + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -13386,7 +13454,7 @@ turbo@^1.10.12: turbo-windows-64 "1.11.3" turbo-windows-arm64 "1.11.3" -tweetnacl@^1.0.1, tweetnacl@^1.0.3: +tweetnacl@1.0.3, tweetnacl@^1.0.1, tweetnacl@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== @@ -14149,6 +14217,11 @@ zip-stream@^4.1.0: compress-commons "^4.1.2" readable-stream "^3.6.0" +zod@^3.21.4: + version "3.23.8" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" + integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== + zod@^3.22.4: version "3.22.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff"