import { Address, beginCell, Cell, Contract, contractAddress, ContractProvider, Sender, SendMode } from '@ton/core'; export type UniversalWalletContractConfig = { subwalletId: number, publicKey: Buffer, admin: Address, memCode: Cell }; export function universalWalletContractConfigToCell(config: UniversalWalletContractConfig): Cell { if (config.publicKey.length !== 32) throw new Error('Public key must be 32 bytes long'); return beginCell() .storeUint(config.subwalletId, 32) .storeAddress(config.admin) .storeRef( beginCell() .storeBuffer(config.publicKey) .storeRef(config.memCode) .endCell() ) .endCell(); } export class UniversalWalletContract implements Contract { constructor(readonly address: Address, readonly init?: { code: Cell; data: Cell }) {} static createFromAddress(address: Address) { return new UniversalWalletContract(address); } static createFromConfig(config: UniversalWalletContractConfig, code: Cell, workchain = 0) { const data = universalWalletContractConfigToCell(config); const init = { code, data }; return new UniversalWalletContract(contractAddress(workchain, init), init); } async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, body: beginCell() .endCell(), }); } async sendAdminProvideMessage(provider: ContractProvider, via: Sender, value: bigint, messages: {rawMsg: Cell, msgMode: number}[], queryId: number = 0) { let messagesPacked = beginCell(); for (const {rawMsg, msgMode} of messages) { messagesPacked = messagesPacked.storeUint(msgMode, 8).storeRef(rawMsg); console.log(msgMode, rawMsg); } await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, body: beginCell() .storeUint(0xA173, 32) .storeUint(queryId, 64) .storeSlice(messagesPacked.endCell().beginParse()) .endCell(), }); } async sendSignedRequest(provider: ContractProvider, via: Sender, value: bigint, signedRequest: Cell, query_id: number = 0) { await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, body: beginCell() .storeUint(0xA174, 32) .storeSlice(signedRequest.beginParse()) .endCell(), }); } async sendEditCode(provider: ContractProvider, via: Sender, value: bigint, newCode: Cell, newData: Cell) { await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, body: beginCell() .storeUint(0xA183, 32) .storeUint(0, 64) .storeRef(newCode) .storeRef(newData) .endCell(), }); } async getWalletData(provider: ContractProvider) { let stack = (await provider.get('get_wallet_data', [])).stack; return { subwalletId: stack.readNumber(), admin: stack.readAddress() } } async getMessageStates(provider: ContractProvider) { let stack = (await provider.get('get_message_states', [])).stack; return { publicKey: stack.readBigNumber(), memCode: stack.readCell() }; } }