import { BigNumberish, ethers, Wallet as HDNodeWallet } from "ethers"; import { getWeb3Endpoint, getNewApiEndpoint, NETWORKS, getMultiCallAddresses, getMultiSigAddresses, getWeb3NodeETH, getWeb3NodeBSC, getGasCenterAddresses, getChecksAddresses } from "../endpoints"; import Wallet from "../wallet"; import DecimalContractEVM from "./contract"; import Call, { NFTCollectionReserveless } from "./call"; import {TypeNFT, Token, NFTCollection, ValidotorStake} from "./call"; import { TokenType, NFTStake } from "./interfaces/delegation"; import { ValidatorMeta, ValidatorStatus } from "./interfaces/validator"; import Subgraph from "../subgraph"; import { DecimalContract } from "../subgraph/interfaces/contracts"; import IPFS from "./ipfs"; import { abi as multiCallAbi } from "./abi/Multicall.json"; import { abi as checksAbi } from "./abi/Checks.json"; import { buildSafeTransaction, safeApproveHash, SafeSignature, SafeTransaction, MetaTransaction } from "./multisig/execution"; import { buildMultiSendSafeTx } from "./multisig/multisend"; import { Blob } from "buffer"; export default class DecimalEVM { private readonly network: NETWORKS; private readonly wallet: Wallet; private readonly apiUrl: string; private readonly subgraph: Subgraph; private readonly ipfs: IPFS; private call?: Call; private contractAddesses?: DecimalContract[]; public provider: ethers.providers.JsonRpcProvider; public account: HDNodeWallet; public providerETH?: ethers.providers.JsonRpcProvider; public accountETH?: HDNodeWallet; public providerBSC?: ethers.providers.JsonRpcProvider; public accountBSC?: HDNodeWallet; private contracts: { [address: string]: DecimalContractEVM } = {} private abis: { token?: ethers.ContractInterface, tokenReserveless?: ethers.ContractInterface, drc721?: ethers.ContractInterface, drc1155?: ethers.ContractInterface, drc721Reserveless?: ethers.ContractInterface, drc1155Reserveless?: ethers.ContractInterface, } = { token: undefined, drc721: undefined, drc1155: undefined, drc721Reserveless: undefined, drc1155Reserveless: undefined, } public multisig = <{ create: (ownersData: { owner: string; weight: number; }[], weightThreshold?: number, estimateGas?: boolean) => Promise<{ tx: any; multisigAddress: any; estimateGas: any; }>; buildTxSendDEL: (safeAddress: string, to: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxSendToken: (safeAddress: string, tokenAddress: string, to: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxBurnToken: (safeAddress: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxSendNFT: (safeAddress: string, tokenAddress: string, to: string, tokenId: string | number | bigint, amount?: string | number | bigint, nonce?: BigNumberish) => Promise buildTxDelegateDEL: (safeAddress: string, validator: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxDelegateToken: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxDelegateDRC721: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxDelegateDRC1155: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxTransferStakeToken: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, newValidator: string, nonce?: BigNumberish) => Promise; buildTxTransferStakeNFT: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, newValidator: string, nonce?: BigNumberish) => Promise; buildTxWithdrawStakeToken: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxWithdrawStakeNFT: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxDelegateDELHold: (safeAddress: string, validator: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish) => Promise; buildTxDelegateTokenHold: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish) => Promise; buildTxTransferStakeTokenHold: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, newValidator: string, nonce?: BigNumberish) => Promise; buildTxWithdrawStakeTokenHold: (safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish) => Promise; buildTxDelegateNFT: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxDelegateNFT1155: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxWithdrawNFT: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxWithdrawNFT1155: (safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish) => Promise; buildTxTransferNFTStake: (safeAddress: string, oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, nonce?: BigNumberish) => Promise; buildTxTransferNFT1155Stake: (safeAddress: string, oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, nonce?: BigNumberish) => Promise; buildTxSetFallbackHandler: (safeAddress: string, handlerAddress?: string, nonce?: BigNumberish) => Promise; signTx: (safeAddress: string, safeTx: SafeTransaction) => Promise; approveHash: (safeAddress: string, safeTx: SafeTransaction) => Promise<{ safeTransaction: SafeSignature, tx: any }>; approveHashEstimateGas: (safeAddress: string, safeTx: SafeTransaction) => Promise executeTx: (safeAddress: string, safeTx: SafeTransaction, signatures: SafeSignature[], estimateGas?: boolean) => Promise; getNonce: (safeAddress: string) => Promise; getCurrentApproveTransactions: (safeAddress: string) => Promise<{transactions: SafeTransaction[]; approvers: string[];}> getExpiredApproveTransactions: (safeAddress: string) => Promise<{transactions: SafeTransaction[]; approvers: string[];}> getSignatureForParticipant: (participantAddress: string) => Promise decodeTransaction: (safeTx: SafeTransaction) => { action: string; tokenType: string; token: string; to: string; tokenId?: string; amount?: string; newValidator?: string; holdTimestamp?: string; } }>{ create: this.createMultiSig.bind(this), buildTxSendDEL: this.buildMultiSigTxSendDEL.bind(this), buildTxSendToken: this.buildMultiSigTxSendToken.bind(this), buildTxBurnToken: this.buildMultiSigTxBurnToken.bind(this), buildTxSendNFT: this.buildMultiSigTxSendNFT.bind(this), buildTxDelegateDEL: this.buildMultiSigTxDelegateDEL.bind(this), buildTxDelegateToken: this.buildMultiSigTxDelegateToken.bind(this), buildTxDelegateDRC721: this.buildMultiSigTxDelegateDRC721.bind(this), buildTxDelegateDRC1155: this.buildMultiSigTxDelegateDRC1155.bind(this), buildTxTransferStakeToken: this.buildMultiSigTxTransferStakeToken.bind(this), buildTxTransferStakeNFT: this.buildMultiSigTxTransferStakeNFT.bind(this), buildTxWithdrawStakeToken: this.buildMultiSigTxWithdrawStakeToken.bind(this), buildTxWithdrawStakeNFT: this.buildMultiSigTxWithdrawStakeNFT.bind(this), buildTxDelegateDELHold: this.buildMultiSigTxDelegateDELHold.bind(this), buildTxDelegateTokenHold: this.buildMultiSigTxDelegateTokenHold.bind(this), buildTxTransferStakeTokenHold: this.buildMultiSigTxTransferStakeTokenHold.bind(this), buildTxWithdrawStakeTokenHold: this.buildMultiSigTxWithdrawStakeTokenHold.bind(this), buildTxDelegateNFT: this.buildMultiSigTxDelegateNFT.bind(this), buildTxDelegateNFT1155: this.buildMultiSigTxDelegateNFT1155.bind(this), buildTxWithdrawNFT: this.buildMultiSigTxWithdrawNFT.bind(this), buildTxWithdrawNFT1155: this.buildMultiSigTxWithdrawNFT1155.bind(this), buildTxTransferNFTStake: this.buildMultiSigTxTransferNFTStake.bind(this), buildTxTransferNFT1155Stake: this.buildMultiSigTxTransferNFT1155Stake.bind(this), buildTxSetFallbackHandler: this.buildMultiSigTxSetFallbackHandler.bind(this), signTx: this.signMultiSigTx.bind(this), approveHash: this.approveHashMultiSig.bind(this), approveHashEstimateGas: this.approveHashMultiSigEstimateGas.bind(this), executeTx: this.executeMultiSigTx.bind(this), getNonce: this.getNonceMultiSig.bind(this), getCurrentApproveTransactions: this.getCurrentApproveTransactions.bind(this), getExpiredApproveTransactions: this.getExpiredApproveTransactions.bind(this), getSignatureForParticipant: this.getSignatureForParticipant.bind(this), decodeTransaction: this.decodeMultiSigSafeTransaction.bind(this), }; public constructor( wallet: Wallet, network: NETWORKS, ) { this.wallet = wallet; this.network = network; this.provider = new ethers.providers.JsonRpcProvider(getWeb3Endpoint(network)); this.account = HDNodeWallet.fromMnemonic(this.wallet.mnemonic!, `m/44'/60'/0'/0/${this.wallet.wallet.id}`).connect(this.provider); this.apiUrl = getNewApiEndpoint(this.network); this.subgraph = new Subgraph(this.network) this.ipfs = new IPFS(this.network) this.call = new Call( this.network, this.provider, this.account ) } private async getContract(address: string, abi?: any) { if (!this.contracts[address]) { this.contracts[address] = await DecimalContractEVM.getContract(this.network, this.apiUrl, this.account, address, abi) } return this.contracts[address] } public async connect(contractName?: string) { if (contractName) { await this.checkConnect(contractName) } else { await this.checkConnect('contract-center') await this.checkConnect('token-center') await this.checkConnect('nft-center') await this.checkConnect('delegation') await this.checkConnect('delegation-nft') await this.checkConnect('master-validator') await this.checkConnect('multi-call') await this.checkConnect('multi-sig') await this.checkConnect('gas-center') await this.checkConnect('checks') //TODO bridge } } private async checkConnect(contractName: string) { if (!this.call) throw new Error('DecimalEVM is not connected'); switch(contractName) { case 'contract-center': if (!this.call.contractCenter) { const contractCenter = await this.initFromImplementation('contract-center'); this.call.setDecimalContractEVM(contractCenter, 'contractCenter') } break; case 'token-center': if (!this.call.tokenCenter) { const tokenCenter = await this.initFromImplementation('token-center'); const [ tokenImplAddress, tokenReservelessImplAddress, ] = await Promise.all([ tokenCenter.contract.implementation(), tokenCenter.contract.implementationReserveless(), ]) const [ tokenImpl, tokenReservelessImpl, ] = await Promise.all([ this.getContract(tokenImplAddress), this.getContract(tokenReservelessImplAddress), ]) this.abis.token = tokenImpl.abi; this.abis.tokenReserveless = tokenReservelessImpl.abi; this.call.setDecimalContractEVM(tokenCenter, 'tokenCenter') } break; case 'nft-center': if (!this.call.nftCenter) { const nftCenter = await this.initFromImplementation('nft-center'); const [ drc721ImplAddress, drc1155ImplAddress, drc721ReservelessImplAddress, drc1155ReservelessImplAddress, ] = await Promise.all([ nftCenter.contract.implementation(TypeNFT.DRC721, true), nftCenter.contract.implementation(TypeNFT.DRC1155, true), nftCenter.contract.implementation(TypeNFT.DRC721, false), nftCenter.contract.implementation(TypeNFT.DRC1155, false), ]) const [ drc721Impl, drc1155Impl, drc721ReservelessImpl, drc1155ReservelessImpl, ] = await Promise.all([ this.getContract(drc721ImplAddress), this.getContract(drc1155ImplAddress), this.getContract(drc721ReservelessImplAddress), this.getContract(drc1155ReservelessImplAddress), ]) this.abis.drc721 = drc721Impl.abi; this.abis.drc1155 = drc1155Impl.abi; this.abis.drc721Reserveless = drc721ReservelessImpl.abi; this.abis.drc1155Reserveless = drc1155ReservelessImpl.abi; this.call.setDecimalContractEVM(nftCenter, 'nftCenter') } break; case 'delegation': if (!this.call.delegation) { const delegation = await this.initFromImplementation('delegation'); this.call.setDecimalContractEVM(delegation, 'delegation') } break; case 'delegation-nft': if (!this.call.delegationNft) { const delegationNft = await this.initFromImplementation('delegation-nft'); this.call.setDecimalContractEVM(delegationNft, 'delegationNft') } break; case 'master-validator': if (!this.call.masterValidator) { const masterValidator = await this.initFromImplementation('master-validator'); this.call.setDecimalContractEVM(masterValidator, 'masterValidator') } break; case 'multi-call': if (!this.call.multiCall) { const multiCall = await this.getContract(getMultiCallAddresses(this.network), multiCallAbi); this.call.setDecimalContractEVM(multiCall, 'multiCall') } break; case 'multi-sig': if (!this.call.safe) { const [ safe, safeFactory, multiSend ] = await Promise.all([ this.getContract(getMultiSigAddresses(this.network).safe), this.getContract(getMultiSigAddresses(this.network).safeFactory), this.getContract(getMultiSigAddresses(this.network).multiSend) ]) this.call.setDecimalContractEVM(multiSend, 'multiSend') this.call.setDecimalContractEVM(safe, 'safe') this.call.setDecimalContractEVM(safeFactory, 'safeFactory') } break; case 'bridge': if (!this.call.bridgeV2) { const bridgeContracts = await this.subgraph.getBridgeContracts() const abi = (await this.getContract(bridgeContracts.implementation)).abi const bridgeV2 = await this.getContract(bridgeContracts.id, abi); this.call.setDecimalContractEVM(bridgeV2, 'bridgeV2') this.providerETH = new ethers.providers.JsonRpcProvider(getWeb3NodeETH(this.network)); this.accountETH = HDNodeWallet.fromMnemonic(this.wallet.mnemonic!, `m/44'/60'/0'/0/${this.wallet.wallet.id}`).connect(this.providerETH); this.providerBSC = new ethers.providers.JsonRpcProvider(getWeb3NodeBSC(this.network)); this.accountBSC = HDNodeWallet.fromMnemonic(this.wallet.mnemonic!, `m/44'/60'/0'/0/${this.wallet.wallet.id}`).connect(this.providerBSC); } break; case 'gas-center': if (!this.call.gasCenter) { const gasCenter = await this.getContract(getGasCenterAddresses(this.network)); this.call.setDecimalContractEVM(gasCenter, 'gasCenter') } break; case 'checks': if (!this.call.checks) { const checks = await this.getContract(getChecksAddresses(this.network), checksAbi); this.call.setDecimalContractEVM(checks, 'checks') } break; default: throw new Error(`Unknown contract pack name '${contractName}'`); } } private async initFromImplementation( contractName: string) { if (!this.contractAddesses) this.contractAddesses = await this.subgraph.getDecimalContracts(); const contract = this.contractAddesses?.find((contract) => contract.name == contractName) if (!contract) throw new Error(`${contractName } not found in thegraph`); const abi = (await this.getContract(contract.implementation)).abi return await this.getContract(contract.address, abi) } public async parseMemo(txHash: string): Promise { await this.checkConnect('multi-call') const tx = await this.provider.getTransaction(txHash); if (tx.data && tx.data !== '0x') { try { const decodedInput = this.call!.multiCall?.contract.interface.decodeFunctionData("aggregate", tx.data); if (decodedInput) { const calls = decodedInput[0]; const call = calls.find((call: any) => call.target == ethers.constants.AddressZero && call.value == "0" && call.callData != "0x") if (call) return ethers.utils.toUtf8String(call.callData); } return } catch (error) { return } } return } // write function public async multiCall(callData: { target: string; value: string | number | bigint | BigNumberish; iface: string; params: any; }[], memo?: string, estimateGas?: boolean) { await this.checkConnect('multi-call') let calls: { target: string; value: string; callData: string; }[] = []; let valueSum: ethers.BigNumber = ethers.BigNumber.from(0); for (let i = 0; i < callData.length; i++) { let data: string; if (!!callData[i].iface) { const iFace = new ethers.utils.Interface([callData[i].iface]); const func = iFace.functions[Object.keys(iFace.functions)[0]] if (callData[i].params.length != Object.keys(func.inputs).length) throw Error(`The length of 'params' does not match the length of 'iface'`); data = iFace.encodeFunctionData(func.name, callData[i].params) } else { if (callData[i].params.length != 0) throw Error(`The length of 'params' does not match the length of 'iface'`); data = "0x"; } calls.push({ target: callData[i].target, value: callData[i].value.toString(), callData: data }) valueSum = valueSum.add(ethers.BigNumber.from(callData[i].value)) } if (memo) { const memoHex = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(memo)); calls.push({ target: ethers.constants.AddressZero, value: "0", callData: memoHex }) } return await this.call!.multicall(valueSum.toString(), calls, estimateGas) } public async multiSendToken(multiData: { token: string; to: string; amount: any; }[], memo?: string, estimateGas?: boolean) { const owner = this.account.address const spender = await this.getDecimalContractAddress('multi-call') let amountSum: {[token:string]: ethers.BigNumber} = {} let callDatas: { target: string; value: string | number | bigint | BigNumberish; iface: string; params: any; }[] = []; for (let i = 0; i < multiData.length; i++) { const tokenAddress = multiData[i].token; if (tokenAddress == 'del') continue; if (!amountSum[tokenAddress]) amountSum[tokenAddress] = ethers.BigNumber.from(0); amountSum[tokenAddress] = amountSum[tokenAddress].add(ethers.BigNumber.from(multiData[i].amount)) } for (const tokenAddress of Object.keys(amountSum)) { const sign = await this.getSignPermitToken(tokenAddress, spender, amountSum[tokenAddress].toString()) const deadline = ethers.constants.MaxUint256 callDatas.push({ target: tokenAddress, value: 0, iface: "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)", params: [owner, spender, amountSum[tokenAddress], deadline, sign?.v, sign?.r, sign?.s ] }) } for (let i = 0; i < multiData.length; i++) { const tokenAddress = multiData[i].token if (tokenAddress == 'del') { const to = multiData[i].to const amount = multiData[i].amount callDatas.push({ target: to, value: amount, iface: "", params: [] }) } else { const to = multiData[i].to const amount = multiData[i].amount callDatas.push({ target: tokenAddress, value: 0, iface: "function transferFrom(address from, address to, uint256 value)", params: [owner, to, amount] }) } } return await this.multiCall(callDatas, memo, estimateGas) } public async sendDEL(address: string, amount: string | number | bigint | BigNumberish, estimateGas?: boolean) { if (estimateGas) { return await this.account.estimateGas({ to: address, value: amount }); } return await this.account.sendTransaction({ to: address, value: amount }).then((tx: ethers.ContractTransaction) => tx.wait()); } public async burnDEL(amount: string | number | bigint | BigNumberish, estimateGas?: boolean) { return this.sendDEL(ethers.constants.AddressZero, amount, estimateGas) } public async createToken(payload: Token, reserve: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); return await this.call!.createToken(payload, reserve, estimateGas) } public async createTokenReserveless( name: string, symbol: string, mintable: boolean, burnable: boolean, initialMint: string | number | bigint, cap: string | number | bigint | undefined | null, identity: string, estimateGas?: boolean ) { await this.checkConnect('token-center'); return await this.call!.createTokenReserveless( name, symbol, mintable, burnable, initialMint, cap, identity, estimateGas ); } public async convertToken(tokenIn:string, tokenOut: string, amountIn: string | number | bigint, amountOutMin: string | number | bigint, recipient: string, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('token-center'); return await this.call!.convertToken(tokenIn, tokenOut, amountIn, amountOutMin, recipient, sign, estimateGas) } public async approveToken(tokenAddress: string, spender: string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.approveToken(token.contract, spender, amount, estimateGas) } public async transferToken(tokenAddress: string, to: string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.transferToken(token.contract, to, amount, estimateGas) } public async transferFromToken(tokenAddress: string, from: string, to: string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.transferFromToken(token.contract, from, to, amount, estimateGas) } public async burnToken(tokenAddress: string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.burnToken(token.contract, amount, estimateGas) } public async mintTokenReserveless(tokenAddress: string, amount: string | number | bigint, recipient: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.tokenReserveless) return await this.call!.mintTokenReserveless(token.contract, amount, recipient, estimateGas) } public async convertToDEL(owner: string, token: string, amount: string | number | bigint, estimateGas: string | number | bigint, sign: ethers.Signature, estimateGasUsage?: boolean) { await this.checkConnect('gas-center'); const deadline = ethers.constants.MaxUint256; return await this.call!.convertToDEL(owner, token, amount, estimateGas, sign, estimateGasUsage); } public async buyTokenForExactDEL(tokenAddress: string, amountDel: string | number | bigint, amountOutMin: string | number | bigint, recipient: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.buyTokenForExactDEL(token.contract, amountDel, amountOutMin, recipient, estimateGas) } public async buyExactTokenForDEL(tokenAddress: string, amountDel: string | number | bigint, amountOut: string | number | bigint, recipient: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.buyExactTokenForDEL(token.contract, amountDel, amountOut, recipient, estimateGas) } public async sellTokensForExactDEL(tokenAddress: string, amountOut: string | number | bigint, amountInMax: string | number | bigint, recipient: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.sellTokensForExactDEL(token.contract, amountOut, amountInMax, recipient, estimateGas) } public async sellExactTokensForDEL(tokenAddress: string, amountIn: string | number | bigint, amountOutMin: string | number | bigint, recipient: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.sellExactTokensForDEL(token.contract, amountIn, amountOutMin, recipient, estimateGas) } public async updateTokenIdentity(tokenAddress: string, newIdentity: string, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token); return await this.call!.updateTokenIdentity(token.contract, newIdentity, estimateGas) } public async updateTokenMaxTotalSupply(tokenAddress: string, newMaxTotalSupply: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token); return await this.call!.updateTokenMaxTotalSupply(token.contract, newMaxTotalSupply, estimateGas) } public async updateTokenMinTotalSupply(tokenAddress: string, newMinTotalSupply: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token); return await this.call!.updateTokenMinTotalSupply(token.contract, newMinTotalSupply, estimateGas) } public async permitToken(tokenAddress: string, owner: string, spender: string, amount: string | number | bigint, sign: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('token-center'); const token = await this.getContract(tokenAddress, this.abis?.token) return await this.call!.permitToken(token.contract, owner, spender, amount, sign, estimateGas) } public async createCollectionDRC721(payload:NFTCollection, estimateGas?: boolean) { await this.checkConnect('nft-center'); return await this.call!.createCollection(payload, TypeNFT.DRC721, true, estimateGas) } public async createCollectionDRC1155(payload:NFTCollection, estimateGas?: boolean) { await this.checkConnect('nft-center'); return await this.call!.createCollection(payload, TypeNFT.DRC1155, true, estimateGas) } public async createCollectionDRC721Reserveless(payload:NFTCollectionReserveless, estimateGas?: boolean) { await this.checkConnect('nft-center'); return await this.call!.createCollection(payload, TypeNFT.DRC721, false, estimateGas) } public async createCollectionDRC1155Reserveless(payload:NFTCollectionReserveless, estimateGas?: boolean) { await this.checkConnect('nft-center'); return await this.call!.createCollection(payload, TypeNFT.DRC1155, false, estimateGas) } public async approveNFT721(nftCollectionAddress: string, to: string, tokenId: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) if (/*typeNFT != TypeNFT.DRC721Standart && */ typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721 and DRC721Standart`); const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) return await this.call!.approveNFT721(nft.contract, to, tokenId, estimateGas) } public async approveForAllNFT(nftCollectionAddress: string, to: string, approved: boolean, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) return await this.call!.setApprovalForAllNFT(nft.contract, to, approved, estimateGas) } /* public async mintNFT(nftCollectionAddress: string, to: string, tokenURI: string, tokenId?: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { if (!this.call) throw this.isNotConnected; const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { case TypeNFT.DRC721: case TypeNFT.DRC1155: throw new Error(`The ${typeNFT} type is not supported by the mintNFT() method. Try mintNFTWithDELReserve() or mintNFTWithTokenReserve()`) case TypeNFT.DRC721Standart: return await this.call.mintNFT(nft.contract, to, tokenURI, undefined, undefined, estimateGas) case TypeNFT.DRC1155Standart: return await this.call.mintNFT(nft.contract, to, tokenURI, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } */ public async mintReserveless(nftCollectionAddress: string, to: string, tokenURI: string, tokenId?: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { case TypeNFT.DRC721: return await this.call!.mintReserveless(nft.contract, to, tokenURI, tokenId, undefined, estimateGas) case TypeNFT.DRC1155: return await this.call!.mintReserveless(nft.contract, to, tokenURI, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async mintNFTWithDELReserve(nftCollectionAddress: string, to: string, tokenURI: string, reserve: string | number | bigint, tokenId?: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: //case TypeNFT.DRC1155Standart: // throw new Error(`The ${typeNFT} type is not supported by the mintNFTWithDELReserve() and mintNFTWithTokenReserve() methods. Try mintNFT()`) case TypeNFT.DRC721: return await this.call!.mintNFTWithDELReserve(nft.contract, to, tokenURI, reserve, undefined, undefined, estimateGas) case TypeNFT.DRC1155: return await this.call!.mintNFTWithDELReserve(nft.contract, to, tokenURI, reserve, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async mintNFTWithTokenReserve(nftCollectionAddress: string, to: string, tokenURI: string, reserveAmount: string | number | bigint, reserveToken: string, sign?: ethers.Signature, tokenId?: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: //case TypeNFT.DRC1155Standart: // throw new Error(`The ${typeNFT} type is not supported by the mintNFTWithDELReserve() and mintNFTWithTokenReserve() methods. Try mintNFT()`) case TypeNFT.DRC721: return await this.call!.mintNFTWithTokenReserve(nft.contract, to, tokenURI, reserveAmount, reserveToken, sign, undefined, undefined, estimateGas) case TypeNFT.DRC1155: return await this.call!.mintNFTWithTokenReserve(nft.contract, to, tokenURI, reserveAmount, reserveToken, sign, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async addDELReserveNFT(nftCollectionAddress: string, tokenId: string | number | bigint, amountReserve: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: //case TypeNFT.DRC1155Standart: // throw new Error(`The ${typeNFT} type is not supported by the addDELReserveNFT() and addTokenReserveNFT() methods.`) case TypeNFT.DRC721: case TypeNFT.DRC1155: return await this.call!.addDELReserveNFT(nft.contract, tokenId, amountReserve, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async addTokenReserveNFT(nftCollectionAddress: string, tokenId: string | number | bigint, amountReserve: string | number | bigint, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: //case TypeNFT.DRC1155Standart: // throw new Error(`The ${typeNFT} type is not supported by the addDELReserveNFT() and addTokenReserveNFT() methods.`) case TypeNFT.DRC721: case TypeNFT.DRC1155: return await this.call!.addTokenReserveNFT(nft.contract, tokenId, amountReserve, sign, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async transferNFT(nftCollectionAddress: string, from: string, to: string, tokenId: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: case TypeNFT.DRC721: return await this.call!.transferNFT(nft.contract, from, to, tokenId, undefined, estimateGas) //case TypeNFT.DRC1155Standart: case TypeNFT.DRC1155: return await this.call!.transferNFT(nft.contract, from, to, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async transferBatchNFT1155(nftCollectionAddress: string, from: string, to: string, tokenIds: string[] | number[], amounts: string[] | number[], estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) if (/*typeNFT != TypeNFT.DRC1155Standart &&*/ typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155 and DRC1155Standart`); return await this.call!.transferBatchNFT1155(nft.contract, from, to, tokenIds, amounts, estimateGas) } public async disableMintNFT(nftCollectionAddress: string, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) return await this.call!.disableMintNFT(nft.contract, estimateGas) } public async burnNFT(nftCollectionAddress: string, tokenId: string | number | bigint, amount?: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: case TypeNFT.DRC721: return await this.call!.burnNFT(nft.contract, tokenId, undefined, estimateGas) //case TypeNFT.DRC1155Standart: case TypeNFT.DRC1155: return await this.call!.burnNFT(nft.contract, tokenId, amount, estimateGas) default: throw new Error(`The ${typeNFT} type does not exist`) } } // public async setBaseURINFT(nftCollectionAddress: string, baseURI: string, estimateGas?: boolean) { // await this.checkConnect('nft-center'); // const typeNFT = await this.getNftType(nftCollectionAddress) // const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) // return await this.call!.setBaseURINFT(nft.contract, baseURI, estimateGas) // } public async setTokenURINFT(nftCollectionAddress: string, tokenId: string | number | bigint, tokenURI: string, estimateGas?: boolean) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftCollectionAddress) const nft = await this.getNFTContract(nftCollectionAddress, typeNFT) return await this.call!.setTokenURINFT(nft.contract, tokenId, tokenURI, estimateGas) } public async delegateDEL(validator:string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.delegateDEL(validator, amount, estimateGas) } public async delegateDELHold(validator:string, amount: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.delegateDELHold(validator, amount, holdTimestamp, estimateGas) } public async delegateToken(validator:string, tokenAddress: string, amount: string | number | bigint, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.delegateToken(validator, tokenAddress, amount, sign, estimateGas) } public async delegateTokenHold(validator:string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.delegateTokenHold(validator, tokenAddress, amount, holdTimestamp, sign, estimateGas) } public async transferStakeToken(validator:string, tokenAddress: string, amount: string | number | bigint, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.transferStakeToken(validator, tokenAddress, amount, newValidator, estimateGas) } public async transferStakeTokenHold(validator:string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.transferStakeTokenHold(validator, tokenAddress, amount, holdTimestamp, newValidator, estimateGas) } public async withdrawStakeToken(validator:string, tokenAddress: string, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.withdrawStakeToken(validator, tokenAddress, amount, estimateGas) } public async withdrawStakeTokenHold(validator:string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.withdrawStakeTokenHold(validator, tokenAddress, amount, holdTimestamp, estimateGas) } public async stakeTokenToHold(validator:string, tokenAddress: string, amount: string | number | bigint, oldHoldTimestamp: number, newHoldTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.stakeTokenToHold(validator, tokenAddress, amount, oldHoldTimestamp, newHoldTimestamp, estimateGas) } public async stakeTokenResetHold(validator:string, delegator: string, tokenAddress: string, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.stakeTokenResetHold(validator, delegator, tokenAddress, holdTimestamp, estimateGas) } public async stakeTokenResetHoldDEL(validator:string, delegator: string, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.stakeTokenResetHoldDEL(validator, delegator, holdTimestamp, estimateGas) } public async withdrawTokenWithReset(validator:string, tokenAddress: string, amount: string | number | bigint, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.withdrawTokenWithReset(validator, tokenAddress, amount, holdTimestampsToReset, estimateGas) } public async transferTokenWithReset(oldValidator:string, tokenAddress: string, amount: string | number | bigint, newValidator:string, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.transferTokenWithReset(oldValidator, tokenAddress, amount, newValidator, holdTimestampsToReset, estimateGas) } public async holdTokenWithReset(validator:string, tokenAddress: string, amount: string | number | bigint, newHoldTimestamp: number, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.holdTokenWithReset(validator, tokenAddress, amount, newHoldTimestamp, holdTimestampsToReset, estimateGas) } public async applyPenaltyToStakeToken(validator:string, delegator: string, tokenAddress: string, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.applyPenaltyToStakeToken(validator, delegator, tokenAddress, estimateGas) } public async applyPenaltiesToStakeToken(validator:string, delegator: string, tokenAddress: string, estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.applyPenaltiesToStakeToken(validator, delegator, tokenAddress, estimateGas) } public async completeStakeToken(indexes:string[] | number[], estimateGas?: boolean) { await this.checkConnect('delegation'); return await this.call!.completeStakeToken(indexes, estimateGas) } // NFT delegation via main delegation contract (DRC721) public async delegateNFT(validator: string, nftAddress: string, tokenId: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.delegateNFT(validator, nftAddress, BigInt(tokenId), estimateGas); } public async delegateNFTHold(validator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.delegateNFTHold(validator, nftAddress, BigInt(tokenId), holdTimestamp, estimateGas); } public async delegateNFTByPermit(validator: string, nftAddress: string, tokenId: string | number | bigint, sign: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.delegateNFTByPermit(validator, nftAddress, BigInt(tokenId), sign, estimateGas); } public async withdrawNFT(validator: string, nftAddress: string, tokenId: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.withdrawNFT(validator, nftAddress, BigInt(tokenId), estimateGas); } public async withdrawNFTHold(validator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.withdrawNFTHold(validator, nftAddress, BigInt(tokenId), holdTimestamp, estimateGas); } public async transferNFTStake(oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.transferNFTStake(oldValidator, nftAddress, BigInt(tokenId), newValidator, estimateGas); } public async transferNFTStakeHold(oldValidator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.transferNFTStakeHold(oldValidator, nftAddress, BigInt(tokenId), holdTimestamp, newValidator, estimateGas); } // NFT delegation via main delegation contract (DRC1155) public async delegateNFT1155(validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.delegateNFT1155(validator, nftAddress, BigInt(tokenId), BigInt(amount), estimateGas); } public async delegateNFT1155Hold(validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.delegateNFT1155Hold(validator, nftAddress, BigInt(tokenId), BigInt(amount), holdTimestamp, estimateGas); } public async withdrawNFT1155(validator: string, nftAddress: string, tokenId: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.withdrawNFT1155(validator, nftAddress, BigInt(tokenId), estimateGas); } public async withdrawNFT1155Hold(validator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.withdrawNFT1155Hold(validator, nftAddress, BigInt(tokenId), holdTimestamp, estimateGas); } public async transferNFT1155Stake(oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.transferNFT1155Stake(oldValidator, nftAddress, BigInt(tokenId), newValidator, estimateGas); } public async transferNFT1155StakeHold(oldValidator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation'); await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(nftAddress); if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.transferNFT1155StakeHold(oldValidator, nftAddress, BigInt(tokenId), holdTimestamp, newValidator, estimateGas); } // Old delegation-nft methods (deprecated - use delegateNFT/delegateNFT1155 instead) public async delegateDRC721(validator:string, nftAddress: string, tokenId: string | number | bigint, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.delegateDRC721(validator, nftAddress, tokenId, sign, estimateGas) } public async delegateDRC721Hold(validator:string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.delegateDRC721Hold(validator, nftAddress, tokenId, holdTimestamp, sign, estimateGas) } public async delegateDRC1155(validator:string, nftAddress: string, tokenId: string | number | bigint, amount:string | number | bigint, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.delegateDRC1155(validator, nftAddress, tokenId, amount, sign, estimateGas) } public async delegateDRC1155Hold(validator:string, nftAddress: string, tokenId: string | number | bigint, amount:string | number | bigint, holdTimestamp: number, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.delegateDRC1155Hold(validator, nftAddress, tokenId, amount, holdTimestamp, sign, estimateGas) } public async transferStakeNFT(validator:string, nftAddress: string, tokenId: string | number | bigint, amount:string | number | bigint, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.transferStakeNFT(validator, nftAddress, tokenId, amount, newValidator, estimateGas) } public async transferStakeNFTHold(validator:string, nftAddress: string, tokenId: string | number | bigint, amount:string | number | bigint, holdTimestamp: number, newValidator: string, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.transferStakeNFTHold(validator, nftAddress, tokenId, amount, holdTimestamp, newValidator, estimateGas) } public async withdrawStakeNFT(validator:string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.withdrawStakeNFT(validator, nftAddress, tokenId, amount, estimateGas) } public async withdrawStakeNFTHold(validator:string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.withdrawStakeNFTHold(validator, nftAddress, tokenId, amount, holdTimestamp, estimateGas) } public async stakeNFTToHold(validator:string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, oldHoldTimestamp: number, newHoldTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.stakeNFTToHold(validator, nftAddress, tokenId, amount, oldHoldTimestamp, newHoldTimestamp, estimateGas) } public async stakeNFTResetHold(validator:string, delegator: string, nftAddress: string, tokenId: string | number | bigint, holdTimestamp: number, estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.stakeNFTResetHold(validator, delegator, nftAddress, tokenId, holdTimestamp, estimateGas) } public async withdrawNFTWithReset(validator:string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.withdrawNFTWithReset(validator, nftAddress, tokenId, amount, holdTimestampsToReset, estimateGas) } public async transferNFTWithReset(oldValidator:string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, newValidator:string, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.transferNFTWithReset(oldValidator, nftAddress, tokenId, amount, newValidator, holdTimestampsToReset, estimateGas) } public async holdNFTWithReset(validator:string, nftAddress: string, tokenId: string | number | bigint, amountToHold: string | number | bigint, newHoldTimestamp: number, holdTimestampsToReset: number[], estimateGas?: boolean) { await this.checkConnect('delegation-nft'); const typeNFT = await this.getNftType(nftAddress) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.holdNFTWithReset(validator, nftAddress, tokenId, amountToHold, newHoldTimestamp, holdTimestampsToReset, estimateGas) } public async completeStakeNFT(indexes:string[] | number[], estimateGas?: boolean) { await this.checkConnect('delegation-nft'); return await this.call!.completeStakeNFT(indexes, estimateGas) } public async addValidatorWithToken(meta: ValidatorMeta, stake: ValidotorStake, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('master-validator'); const validator = meta.operator_address this.validationValidatorMeta(meta) return await this.call!.addValidatorWithToken(validator, JSON.stringify(meta), stake, sign, estimateGas) } public async addValidatorWithETH(meta: ValidatorMeta, amount: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('master-validator'); const validator = meta.operator_address this.validationValidatorMeta(meta) return await this.call!.addValidatorWithETH(validator, JSON.stringify(meta), amount, estimateGas) } public async removeValidator(validator: string, estimateGas?: boolean) { await this.checkConnect('master-validator'); return await this.call!.removeValidator(validator, estimateGas) } public async pauseValidator(validator: string, estimateGas?: boolean) { await this.checkConnect('master-validator'); return await this.call!.pauseValidator(validator, estimateGas) } public async unpauseValidator(validator: string, estimateGas?: boolean) { await this.checkConnect('master-validator'); return await this.call!.unpauseValidator(validator, estimateGas) } public async updateValidatorMeta(meta: ValidatorMeta, estimateGas?: boolean) { await this.checkConnect('master-validator'); const validator = meta.operator_address this.validationValidatorMeta(meta) return await this.call!.updateValidatorMeta(validator, JSON.stringify(meta), estimateGas) } private async buildMultiSigTxSendDEL(safeAddress: string, to: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ to: to, value: amount, nonce: actualNonce }); } private async buildMultiSigTxSendToken(safeAddress: string, tokenAddress: string, to: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const iFace = new ethers.utils.Interface(["function transfer(address to, uint256 value)"]); const data = iFace.encodeFunctionData('transfer', [to, amount]) const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: tokenAddress, nonce: actualNonce }); } private async buildMultiSigTxBurnToken(safeAddress: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const iFace = new ethers.utils.Interface(["function burn(uint256 amount)"]); const data = iFace.encodeFunctionData('burn', [amount]) const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: tokenAddress, nonce: actualNonce }); } private async buildMultiSigTxSendNFT(safeAddress: string, tokenAddress: string, to: string, tokenId: string | number | bigint, amount?: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) let data: string; if (amount === undefined) { const iFace = new ethers.utils.Interface(["function safeTransferFrom(address from, address to, uint256 tokenId, bytes data)"]); data = iFace.encodeFunctionData('safeTransferFrom', [safeAddress, to, tokenId, "0x"]) } else { const iFace = new ethers.utils.Interface(["function safeTransferFrom(address from, address to, uint256 tokenId, uint256 value, bytes data)"]); data = iFace.encodeFunctionData('safeTransferFrom', [safeAddress, to, tokenId, amount, "0x"]) } const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: tokenAddress, nonce: actualNonce }); } // Delegation private async buildMultiSigTxDelegateDEL(safeAddress: string, validator: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function delegateDEL(address validator)"]); const data = iFace.encodeFunctionData('delegateDEL', [validator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, value: amount, nonce: actualNonce }); } private async buildMultiSigTxDelegateToken(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const approveIFace = new ethers.utils.Interface(["function approve(address spender, uint256 amount)"]); const delegateIFace = new ethers.utils.Interface(["function delegate(address validator, address token, uint256 amount)"]); const txs: MetaTransaction[] = [ { to: tokenAddress, value: 0, data: approveIFace.encodeFunctionData('approve', [delegationAddress, amount]), operation: 0 }, { to: delegationAddress, value: 0, data: delegateIFace.encodeFunctionData('delegate', [validator, tokenAddress, amount]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } private async buildMultiSigTxDelegateDRC721(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation-nft'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationNftAddress = this.call!.getDecimalContract('delegation-nft', true) as string; const approveIFace = new ethers.utils.Interface(["function approve(address to, uint256 tokenId)"]); const delegateIFace = new ethers.utils.Interface(["function delegateDRC721(address validator, address nftAddress, uint256 tokenId)"]); const txs: MetaTransaction[] = [ { to: nftAddress, value: 0, data: approveIFace.encodeFunctionData('approve', [delegationNftAddress, tokenId]), operation: 0 }, { to: delegationNftAddress, value: 0, data: delegateIFace.encodeFunctionData('delegateDRC721', [validator, nftAddress, tokenId]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } private async buildMultiSigTxDelegateDRC1155(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation-nft'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationNftAddress = this.call!.getDecimalContract('delegation-nft', true) as string; const approveIFace = new ethers.utils.Interface(["function setApprovalForAll(address operator, bool approved)"]); const delegateIFace = new ethers.utils.Interface(["function delegateDRC1155(address validator, address nftAddress, uint256 tokenId, uint256 amount)"]); const txs: MetaTransaction[] = [ { to: nftAddress, value: 0, data: approveIFace.encodeFunctionData('setApprovalForAll', [delegationNftAddress, true]), operation: 0 }, { to: delegationNftAddress, value: 0, data: delegateIFace.encodeFunctionData('delegateDRC1155', [validator, nftAddress, tokenId, amount]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } // Redelegate (transfer stake) private async buildMultiSigTxTransferStakeToken(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, newValidator: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function transfer(address validator, address token, uint256 amount, address newValidator)"]); const data = iFace.encodeFunctionData('transfer', [validator, tokenAddress, amount, newValidator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxTransferStakeNFT(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, newValidator: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation-nft'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationNftAddress = this.call!.getDecimalContract('delegation-nft', true) as string; const iFace = new ethers.utils.Interface(["function transfer(address validator, address nftAddress, uint256 tokenId, uint256 amount, address newValidator)"]); const data = iFace.encodeFunctionData('transfer', [validator, nftAddress, tokenId, amount, newValidator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationNftAddress, nonce: actualNonce }); } // Withdraw (unbond) private async buildMultiSigTxWithdrawStakeToken(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function withdraw(address validator, address token, uint256 amount)"]); const data = iFace.encodeFunctionData('withdraw', [validator, tokenAddress, amount]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxWithdrawStakeNFT(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation-nft'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationNftAddress = this.call!.getDecimalContract('delegation-nft', true) as string; const iFace = new ethers.utils.Interface(["function withdraw(address validator, address nftAddress, uint256 tokenId, uint256 amount)"]); const data = iFace.encodeFunctionData('withdraw', [validator, nftAddress, tokenId, amount]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationNftAddress, nonce: actualNonce }); } // === Hold variants for delegate/transfer/withdraw via delegation contract === private async buildMultiSigTxDelegateDELHold(safeAddress: string, validator: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function delegateHoldDEL(address validator, uint256 holdTimestamp)"]); const data = iFace.encodeFunctionData('delegateHoldDEL', [validator, holdTimestamp]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, value: amount, nonce: actualNonce }); } private async buildMultiSigTxDelegateTokenHold(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const approveIFace = new ethers.utils.Interface(["function approve(address spender, uint256 amount)"]); const delegateIFace = new ethers.utils.Interface(["function delegateHold(address validator, address token, uint256 amount, uint256 holdTimestamp)"]); const txs: MetaTransaction[] = [ { to: tokenAddress, value: 0, data: approveIFace.encodeFunctionData('approve', [delegationAddress, amount]), operation: 0 }, { to: delegationAddress, value: 0, data: delegateIFace.encodeFunctionData('delegateHold', [validator, tokenAddress, amount, holdTimestamp]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } private async buildMultiSigTxTransferStakeTokenHold(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, newValidator: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function transferHold(address validator, address token, uint256 amount, uint256 holdTimestamp, address newValidator)"]); const data = iFace.encodeFunctionData('transferHold', [validator, tokenAddress, amount, holdTimestamp, newValidator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxWithdrawStakeTokenHold(safeAddress: string, validator: string, tokenAddress: string, amount: string | number | bigint, holdTimestamp: number, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function withdrawHold(address validator, address token, uint256 amount, uint256 holdTimestamp)"]); const data = iFace.encodeFunctionData('withdrawHold', [validator, tokenAddress, amount, holdTimestamp]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } // === NFT delegation via main delegation contract (DRC721 + DRC1155) === private async buildMultiSigTxDelegateNFT(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const approveIFace = new ethers.utils.Interface(["function approve(address to, uint256 tokenId)"]); const delegateIFace = new ethers.utils.Interface(["function delegateNFT(address validator, address nftAddress, uint256 tokenId)"]); const txs: MetaTransaction[] = [ { to: nftAddress, value: 0, data: approveIFace.encodeFunctionData('approve', [delegationAddress, tokenId]), operation: 0 }, { to: delegationAddress, value: 0, data: delegateIFace.encodeFunctionData('delegateNFT', [validator, nftAddress, tokenId]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } private async buildMultiSigTxDelegateNFT1155(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, amount: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const approveIFace = new ethers.utils.Interface(["function setApprovalForAll(address operator, bool approved)"]); const delegateIFace = new ethers.utils.Interface(["function delegateNFT1155(address validator, address nftAddress, uint256 tokenId, uint256 amount)"]); const txs: MetaTransaction[] = [ { to: nftAddress, value: 0, data: approveIFace.encodeFunctionData('setApprovalForAll', [delegationAddress, true]), operation: 0 }, { to: delegationAddress, value: 0, data: delegateIFace.encodeFunctionData('delegateNFT1155', [validator, nftAddress, tokenId, amount]), operation: 0 } ]; const actualNonce = nonce ?? await safe.contract.nonce(); return await buildMultiSendSafeTx(this.call!.multiSend!.contract, txs, actualNonce); } private async buildMultiSigTxWithdrawNFT(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function withdrawNFT(address validator, address nftAddress, uint256 tokenId)"]); const data = iFace.encodeFunctionData('withdrawNFT', [validator, nftAddress, tokenId]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxWithdrawNFT1155(safeAddress: string, validator: string, nftAddress: string, tokenId: string | number | bigint, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function withdrawNFT1155(address validator, address nftAddress, uint256 tokenId)"]); const data = iFace.encodeFunctionData('withdrawNFT1155', [validator, nftAddress, tokenId]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxTransferNFTStake(safeAddress: string, oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function transferNFT(address oldValidator, address nftAddress, uint256 tokenId, address newValidator)"]); const data = iFace.encodeFunctionData('transferNFT', [oldValidator, nftAddress, tokenId, newValidator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async buildMultiSigTxTransferNFT1155Stake(safeAddress: string, oldValidator: string, nftAddress: string, tokenId: string | number | bigint, newValidator: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); await this.checkConnect('delegation'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const delegationAddress = this.call!.getDecimalContract('delegation', true) as string; const iFace = new ethers.utils.Interface(["function transferNFT1155(address oldValidator, address nftAddress, uint256 tokenId, address newValidator)"]); const data = iFace.encodeFunctionData('transferNFT1155', [oldValidator, nftAddress, tokenId, newValidator]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: delegationAddress, nonce: actualNonce }); } private async signMultiSigTx(safeAddress: string, safeTx: SafeTransaction): Promise { await this.checkConnect('multi-sig'); return await this.call!.signMultiSigTx(safeAddress, safeTx); } private async approveHashMultiSig(safeAddress: string, safeTx: SafeTransaction): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) return await safeApproveHash(this.account, safe.contract, safeTx, false, false) } private async approveHashMultiSigEstimateGas(safeAddress: string, safeTx: SafeTransaction): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) return await safeApproveHash(this.account, safe.contract, safeTx, false, true) } private async getSignatureForParticipant(participantAddress: string): Promise { await this.checkConnect('multi-sig'); return { signer: participantAddress, data: "0x000000000000000000000000" + participantAddress.slice(2) + "0000000000000000000000000000000000000000000000000000000000000000" + "01", }; } private async executeMultiSigTx(safeAddress: string, safeTx: SafeTransaction, signatures: SafeSignature[], estimateGas?: boolean) { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) return await this.call!.executeMultiSigTx(safeTx, signatures, safe.contract, estimateGas) } private async createMultiSig(ownersData: { owner: string; weight: number; }[], weightThreshold?: number, estimateGas?: boolean) { await this.checkConnect('multi-sig'); let totalWeight = 0; for (let i = 0; i < ownersData.length; i++) { if (ownersData[i].weight < 1 || ownersData[i].weight > 1000) throw new Error("Invalid owner weight") totalWeight += ownersData[i].weight } if (weightThreshold === 0) throw new Error("Invalid weightThreshold") if (weightThreshold) { if (weightThreshold > totalWeight) throw new Error("Invalid weightThreshold. weightThreshold must not exceed total weight of owners") } else { weightThreshold = ownersData.reduce((sum, num) => sum + num.weight, 0); } const fallbackHandler = getMultiSigAddresses(this.network).tokenCallbackHandler || undefined; return await this.call!.createMultiSig(ownersData, weightThreshold, estimateGas, fallbackHandler) } private async buildMultiSigTxSetFallbackHandler(safeAddress: string, handlerAddress?: string, nonce?: BigNumberish): Promise { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) const handler = handlerAddress || getMultiSigAddresses(this.network).tokenCallbackHandler; if (!handler) throw new Error("TokenCallbackHandler address is not configured for this network"); const iFace = new ethers.utils.Interface(["function setFallbackHandler(address handler)"]); const data = iFace.encodeFunctionData('setFallbackHandler', [handler]); const actualNonce = nonce ?? await safe.contract.nonce(); return buildSafeTransaction({ data, to: safeAddress, nonce: actualNonce }); } private async getNonceMultiSig(safeAddress: string) { await this.checkConnect('multi-sig'); const safe = await this.getContract(safeAddress, this.call!.safe!.contract.interface) return await this.call!.getNonceMultiSig(safe.contract) } private async getCurrentApproveTransactions(safeAddress: string) { return await this.getApproveTransactions(safeAddress, true) } private async getExpiredApproveTransactions(safeAddress: string) { return await this.getApproveTransactions(safeAddress, false) } private async getApproveTransactions(safeAddress: string, current: boolean) { await this.checkConnect('multi-sig'); const nonce = await this.getNonceMultiSig(safeAddress) const {transactions: transactionData, approvers} = current ? await this.subgraph.getMultisigApproveTransactionsByMultisigAddressAndNonce(safeAddress, nonce, 1000, 0) : await this.subgraph.getMultisigApproveTransactionsByMultisigAddressAndNonceNot(safeAddress, nonce, 1000, 0) return { transactions: transactionData.map((trancastion: any) => { return { ...trancastion, safeTxGas: ethers.BigNumber.from(trancastion.safeTxGas), baseGas: ethers.BigNumber.from(trancastion.baseGas), gasPrice: ethers.BigNumber.from(trancastion.gasPrice), nonce: ethers.BigNumber.from(trancastion.nonce), value: ethers.BigNumber.from(trancastion.value), operation: Number(trancastion.operation == 'Call' ? 0 : 1), } }), approvers } } private decodeMultiSigSafeTransaction(safeTx: SafeTransaction): { action: string; tokenType: string; token: string; to: string; tokenId?: string; amount?: string; newValidator?: string; holdTimestamp?: string; } { // MultiSend transactions (operation == 1, delegateCall) if (safeTx.operation === 1) { const innerTxs = this.decodeMultiSend(safeTx.data); if (innerTxs.length >= 2) { const mainTx = innerTxs[innerTxs.length - 1]; return this.decodeInnerTransaction(mainTx); } } if (safeTx.data == "0x") return { action: 'transfer', tokenType: 'Native', token: 'DEL', to: safeTx.to, amount: safeTx.value.toString() } // Delegate DEL const resultDelegateDEL = this.decodeData("function delegateDEL(address validator)", safeTx.data) if (resultDelegateDEL) return { action: 'delegate', tokenType: 'Native', token: 'DEL', to: resultDelegateDEL[0], amount: safeTx.value.toString() } // Transfer (redelegate) token: 4 params const resultTransferStakeToken = this.decodeData("function transfer(address validator, address token, uint256 amount, address newValidator)", safeTx.data) if (resultTransferStakeToken) return { action: 'redelegate', tokenType: 'DRC20', token: resultTransferStakeToken[1], to: resultTransferStakeToken[0], amount: resultTransferStakeToken[2].toString(), newValidator: resultTransferStakeToken[3] } // Transfer (redelegate) NFT: 5 params const resultTransferStakeNFT = this.decodeData("function transfer(address validator, address nftAddress, uint256 tokenId, uint256 amount, address newValidator)", safeTx.data) if (resultTransferStakeNFT) return { action: 'redelegate', tokenType: 'DRC1155', token: resultTransferStakeNFT[1], to: resultTransferStakeNFT[0], tokenId: resultTransferStakeNFT[2].toString(), amount: resultTransferStakeNFT[3].toString(), newValidator: resultTransferStakeNFT[4] } // Withdraw (unbond) token: 3 params const resultWithdrawToken = this.decodeData("function withdraw(address validator, address token, uint256 amount)", safeTx.data) if (resultWithdrawToken) return { action: 'unbond', tokenType: 'DRC20', token: resultWithdrawToken[1], to: resultWithdrawToken[0], amount: resultWithdrawToken[2].toString() } // Withdraw (unbond) NFT: 4 params const resultWithdrawNFT = this.decodeData("function withdraw(address validator, address nftAddress, uint256 tokenId, uint256 amount)", safeTx.data) if (resultWithdrawNFT) return { action: 'unbond', tokenType: 'DRC1155', token: resultWithdrawNFT[1], to: resultWithdrawNFT[0], tokenId: resultWithdrawNFT[2].toString(), amount: resultWithdrawNFT[3].toString() } // Send token (DRC20 transfer) const resultTransferDRC20 = this.decodeData("function transfer(address to, uint256 value)", safeTx.data) if (resultTransferDRC20) return { action: 'transfer', tokenType: 'DRC20', token: safeTx.to, to: resultTransferDRC20[0], amount: resultTransferDRC20[1].toString() } // Burn token (DRC20) const resultBurnDRC20 = this.decodeData("function burn(uint256 amount)", safeTx.data) if (resultBurnDRC20) return { action: 'burn', tokenType: 'DRC20', token: safeTx.to, to: '0x0000000000000000000000000000000000000000', amount: resultBurnDRC20[0].toString() } const resultTransferDRC721 = this.decodeData("function safeTransferFrom(address from, address to, uint256 tokenId, bytes data)", safeTx.data) if (resultTransferDRC721) return { action: 'transfer', tokenType: 'DRC721', token: safeTx.to, to: resultTransferDRC721[1], tokenId: resultTransferDRC721[2].toString(), } const resultTransferDRC1155 = this.decodeData("function safeTransferFrom(address from, address to, uint256 tokenId, uint256 value, bytes data)", safeTx.data) if (resultTransferDRC1155) return { action: 'transfer', tokenType: 'DRC1155', token: safeTx.to, to: resultTransferDRC1155[1], tokenId: resultTransferDRC1155[2], amount: resultTransferDRC1155[3].toString() } // Delegate DEL Hold const resultDelegateDELHold = this.decodeData("function delegateHoldDEL(address validator, uint256 holdTimestamp)", safeTx.data) if (resultDelegateDELHold) return { action: 'delegate', tokenType: 'Native', token: 'DEL', to: resultDelegateDELHold[0], amount: safeTx.value.toString(), holdTimestamp: resultDelegateDELHold[1].toString() } // Transfer (redelegate) token Hold const resultTransferStakeTokenHold = this.decodeData("function transferHold(address validator, address token, uint256 amount, uint256 holdTimestamp, address newValidator)", safeTx.data) if (resultTransferStakeTokenHold) return { action: 'redelegate', tokenType: 'DRC20', token: resultTransferStakeTokenHold[1], to: resultTransferStakeTokenHold[0], amount: resultTransferStakeTokenHold[2].toString(), holdTimestamp: resultTransferStakeTokenHold[3].toString(), newValidator: resultTransferStakeTokenHold[4] } // Withdraw (unbond) token Hold const resultWithdrawTokenHold = this.decodeData("function withdrawHold(address validator, address token, uint256 amount, uint256 holdTimestamp)", safeTx.data) if (resultWithdrawTokenHold) return { action: 'unbond', tokenType: 'DRC20', token: resultWithdrawTokenHold[1], to: resultWithdrawTokenHold[0], amount: resultWithdrawTokenHold[2].toString(), holdTimestamp: resultWithdrawTokenHold[3].toString() } // Withdraw NFT (DRC721) via delegation const resultWithdrawNFTviaDelegation = this.decodeData("function withdrawNFT(address validator, address nftAddress, uint256 tokenId)", safeTx.data) if (resultWithdrawNFTviaDelegation) return { action: 'unbond', tokenType: 'DRC721', token: resultWithdrawNFTviaDelegation[1], to: resultWithdrawNFTviaDelegation[0], tokenId: resultWithdrawNFTviaDelegation[2].toString() } // Withdraw NFT (DRC1155) via delegation const resultWithdrawNFT1155 = this.decodeData("function withdrawNFT1155(address validator, address nftAddress, uint256 tokenId)", safeTx.data) if (resultWithdrawNFT1155) return { action: 'unbond', tokenType: 'DRC1155', token: resultWithdrawNFT1155[1], to: resultWithdrawNFT1155[0], tokenId: resultWithdrawNFT1155[2].toString() } // Transfer (redelegate) NFT (DRC721) via delegation const resultTransferNFT = this.decodeData("function transferNFT(address oldValidator, address nftAddress, uint256 tokenId, address newValidator)", safeTx.data) if (resultTransferNFT) return { action: 'redelegate', tokenType: 'DRC721', token: resultTransferNFT[1], to: resultTransferNFT[0], tokenId: resultTransferNFT[2].toString(), newValidator: resultTransferNFT[3] } // Transfer (redelegate) NFT (DRC1155) via delegation const resultTransferNFT1155 = this.decodeData("function transferNFT1155(address oldValidator, address nftAddress, uint256 tokenId, address newValidator)", safeTx.data) if (resultTransferNFT1155) return { action: 'redelegate', tokenType: 'DRC1155', token: resultTransferNFT1155[1], to: resultTransferNFT1155[0], tokenId: resultTransferNFT1155[2].toString(), newValidator: resultTransferNFT1155[3] } throw Error('Dot') } private decodeInnerTransaction(tx: MetaTransaction): { action: string; tokenType: string; token: string; to: string; tokenId?: string; amount?: string; newValidator?: string; holdTimestamp?: string; } { // Delegate token const resultDelegateToken = this.decodeData("function delegate(address validator, address token, uint256 amount)", tx.data) if (resultDelegateToken) return { action: 'delegate', tokenType: 'DRC20', token: resultDelegateToken[1], to: resultDelegateToken[0], amount: resultDelegateToken[2].toString() } // Delegate DRC721 const resultDelegateDRC721 = this.decodeData("function delegateDRC721(address validator, address nftAddress, uint256 tokenId)", tx.data) if (resultDelegateDRC721) return { action: 'delegate', tokenType: 'DRC721', token: resultDelegateDRC721[1], to: resultDelegateDRC721[0], tokenId: resultDelegateDRC721[2].toString() } // Delegate DRC1155 const resultDelegateDRC1155 = this.decodeData("function delegateDRC1155(address validator, address nftAddress, uint256 tokenId, uint256 amount)", tx.data) if (resultDelegateDRC1155) return { action: 'delegate', tokenType: 'DRC1155', token: resultDelegateDRC1155[1], to: resultDelegateDRC1155[0], tokenId: resultDelegateDRC1155[2].toString(), amount: resultDelegateDRC1155[3].toString() } // Delegate Token Hold (inner of MultiSend after approve) const resultDelegateTokenHold = this.decodeData("function delegateHold(address validator, address token, uint256 amount, uint256 holdTimestamp)", tx.data) if (resultDelegateTokenHold) return { action: 'delegate', tokenType: 'DRC20', token: resultDelegateTokenHold[1], to: resultDelegateTokenHold[0], amount: resultDelegateTokenHold[2].toString(), holdTimestamp: resultDelegateTokenHold[3].toString() } // Delegate NFT (DRC721) via delegation const resultDelegateNFT = this.decodeData("function delegateNFT(address validator, address nftAddress, uint256 tokenId)", tx.data) if (resultDelegateNFT) return { action: 'delegate', tokenType: 'DRC721', token: resultDelegateNFT[1], to: resultDelegateNFT[0], tokenId: resultDelegateNFT[2].toString() } // Delegate NFT (DRC1155) via delegation const resultDelegateNFT1155 = this.decodeData("function delegateNFT1155(address validator, address nftAddress, uint256 tokenId, uint256 amount)", tx.data) if (resultDelegateNFT1155) return { action: 'delegate', tokenType: 'DRC1155', token: resultDelegateNFT1155[1], to: resultDelegateNFT1155[0], tokenId: resultDelegateNFT1155[2].toString(), amount: resultDelegateNFT1155[3].toString() } throw Error('Unknown MultiSend inner transaction') } private decodeMultiSend(data: string): MetaTransaction[] { try { const multiSendIFace = new ethers.utils.Interface(["function multiSend(bytes transactions)"]); const decoded = multiSendIFace.decodeFunctionData('multiSend', data); const txsBytes = ethers.utils.arrayify(decoded[0]); const txs: MetaTransaction[] = []; let offset = 0; while (offset < txsBytes.length) { const operation = txsBytes[offset]; offset += 1; const to = ethers.utils.getAddress(ethers.utils.hexlify(txsBytes.slice(offset, offset + 20))); offset += 20; const value = ethers.BigNumber.from(txsBytes.slice(offset, offset + 32)); offset += 32; const dataLength = ethers.BigNumber.from(txsBytes.slice(offset, offset + 32)).toNumber(); offset += 32; const txData = ethers.utils.hexlify(txsBytes.slice(offset, offset + dataLength)); offset += dataLength; txs.push({ operation, to, value, data: txData }); } return txs; } catch { return []; } } private decodeData(interFace: string, data: string) { try { const iFace = new ethers.utils.Interface([interFace]); const func = iFace.functions[Object.keys(iFace.functions)[0]] return iFace.decodeFunctionData(func.name, data) } catch { return undefined } } public async bridgeTransferNative(to: string, amount: string | number | bigint, serviceFee: string | number | bigint, fromChainId: number, toChainId: number, estimateGas?: boolean) { await this.checkConnect('bridge'); const {bridgeAddress, account} = await this.getAccountAndBridge(fromChainId) if (!bridgeAddress || !account) throw new Error('invalid toChainId') const abi = this.call!.bridgeV2!.abi const contract = new ethers.Contract(bridgeAddress, abi, account); return await this.call!.wrapAndTransferETH(contract, to, amount, serviceFee, toChainId, estimateGas); } public async bridgeTransferTokens(tokenAddress: string, to: string, amount: string | number | bigint, serviceFee: string | number | bigint, fromChainId: number, toChainId: number, estimateGas?: boolean) { await this.checkConnect('bridge'); const {bridgeAddress, account} = await this.getAccountAndBridge(fromChainId) if (!bridgeAddress || !account) throw new Error('invalid toChainId') const abi = this.call!.bridgeV2!.abi const contract = new ethers.Contract(bridgeAddress, abi, account); return await this.call!.transferTokens(contract, tokenAddress, to, amount, serviceFee, toChainId, estimateGas); } public async bridgeCompleteTransfer(toChainId: number, encodedVM: string, unwrapWETH: boolean, estimateGas?: boolean) { // chain id (1 is ETH, 56 is BSC, 75 is DSC) await this.checkConnect('bridge'); const {bridgeAddress, account} = await this.getAccountAndBridge(toChainId) if (!bridgeAddress || !account) throw new Error('invalid toChainId') const abi = this.call!.bridgeV2!.abi const contract = new ethers.Contract(bridgeAddress, abi, account); return await this.call!.completeTransfer(contract, encodedVM, unwrapWETH, estimateGas); } private async getAccountAndBridge(chain: number) { if (!this.call) throw new Error('DecimalEVM is not connected'); switch(chain) { case 1: const bridgeETH = await this.subgraph.getBridgeETHContracts() return {bridgeAddress: bridgeETH.id, account: this.accountETH}; case 56: const bridgeBSC = await this.subgraph.getBridgeBSCContracts() return {bridgeAddress: bridgeBSC.id, account: this.accountBSC}; case 75: return {bridgeAddress: this.call!.bridgeV2!.contract.address, account: this.account}; default: throw new Error(`Unknown chainId '${chain}'`); } } private passwordToPrivateKey(password: string): string { if (!password || typeof password !== 'string') { throw new Error('Password must be a non-empty string'); } return ethers.utils.id(password); } public async createChecksDEL(passwords: string[], amount: string | number | bigint, dueBlock: string | number | bigint, estimateGas?: boolean) { await this.checkConnect('checks'); const privateKeys = passwords.map(pwd => this.passwordToPrivateKey(pwd)); const signers = privateKeys.map(pk => new ethers.Wallet(pk).address); return await this.call!.createChecksDEL(signers, amount, dueBlock, estimateGas); } public async createChecksToken(passwords: string[], amount: string | number | bigint, dueBlock: string | number | bigint, tokenAddress: string, sign?: ethers.Signature, estimateGas?: boolean) { await this.checkConnect('checks'); const privateKeys = passwords.map(pwd => this.passwordToPrivateKey(pwd)); const signers = privateKeys.map(pk => new ethers.Wallet(pk).address); return await this.call!.createChecksToken(signers, amount, dueBlock, tokenAddress, sign, estimateGas); } public async redeemChecks(passwords: string[], checks: string[], estimateGas?: boolean) { await this.checkConnect('checks'); const privateKeys = passwords.map(pwd => this.passwordToPrivateKey(pwd)); const redeemerAddress = this.account.address; let signatures = await Promise.all( privateKeys.map((privateKey, index) => { const signer = new ethers.Wallet(privateKey); // Hash checkHash with redeemer address before signing to match Solidity contract verification const messageToSign = ethers.utils.solidityKeccak256( ['bytes32', 'address'], [checks[index], redeemerAddress] ); return signer.signMessage(ethers.utils.arrayify(messageToSign)); }) ); return await this.call!.redeemChecks(signatures, checks, false, estimateGas); } public async redeemChecksTest(passwords: string[], checks: string[]) { await this.checkConnect('checks'); return await this.call!.redeemChecks(passwords, checks, true, false); } // view function public async getBalance(address: string) { return await this.provider.getBalance(address) } public async getBalanceETH(address: string) { await this.checkConnect('bridge'); return await this.providerETH!.getBalance(address) } public async getBalanceBNB(address: string) { await this.checkConnect('bridge'); return await this.providerBSC!.getBalance(address) } public async getNftType(address: string): Promise { const type = await this.subgraph.getNftCollectionType(address) if (type == null) throw new Error("The nft collection does not exist") let typeNFT: TypeNFT = TypeNFT[type as keyof typeof TypeNFT] return typeNFT } public async getNftTypeFromContract(address: string) { await this.checkConnect('nft-center'); return await this.call!.getNftType(address) } public async getAddressTokenBySymbol(symbol: string) { await this.checkConnect('token-center'); return await this.call!.getAddressTokenBySymbol(symbol) } public async checkTokenExists(address: string) { await this.checkConnect('token-center'); return await this.call!.checkTokenExists(address) } public async getCommissionSymbol(symbol:string) { await this.checkConnect('token-center'); return await this.call!.getCommissionSymbol(symbol) } public async calculateBuyOutput(address: string, amount: string | number | bigint) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.calculateBuyOutput(token.contract, amount) } public async calculateBuyInput(address: string, amount: string | number | bigint) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.calculateBuyInput(token.contract, amount) } public async calculateSellInput(address: string, amount: string | number | bigint) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.calculateSellInput(token.contract, amount) } public async calculateSellOutput(address: string, amount: string | number | bigint) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.calculateSellOutput(token.contract, amount) } public async getSignPermitToken(address: string, spender: string, amount: string | number | bigint): Promise { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.getSignPermitToken(token.contract, spender, amount) } public async allowanceToken(address: string, owner: string, spender: string) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.allowanceToken(token.contract, owner, spender) } public async balanceOfToken(address: string, account: string) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.balanceOfToken(token.contract, account) } public async supportsInterfaceToken(address: string, interfaceId: string) { await this.checkConnect('token-center'); const token = await this.getContract(address, this.abis?.token) return await this.call!.supportsInterfaceToken(token.contract, interfaceId) } public async getApprovedNFT721(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(address) if (/*typeNFT != TypeNFT.DRC721Standart &&*/ typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721 and DRC721Standart`); const nft = await this.getNFTContract(address, typeNFT) return await this.call!.getApprovedNFT721(nft.contract, tokenId) } public async getAllowMintNFT(address: string) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) return await this.call!.getAllowMintNFT(nft.contract) } public async isApprovedForAllNFT(address: string, owner: string, operator: string) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) return await this.call!.isApprovedForAllNFT(nft.contract, owner, operator) } public async ownerOfNFT721(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT = await this.getNftType(address) if (/*typeNFT != TypeNFT.DRC721Standart &&*/ typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721 and DRC721Standart`); const nft = await this.getNFTContract(address, typeNFT) return await this.call!.ownerOfNFT721(nft.contract, tokenId) } public async getTokenURINFT(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: case TypeNFT.DRC721: return await this.call!.getTokenURINFT721(nft.contract, tokenId) //case TypeNFT.DRC1155Standart: case TypeNFT.DRC1155: return await this.call!.getTokenURINFT1155(nft.contract, tokenId) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async balanceOfNFT(address: string, account:string, tokenId?: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) switch (+TypeNFT[TypeNFT[typeNFT] as keyof typeof TypeNFT]) { //case TypeNFT.DRC721Standart: case TypeNFT.DRC721: return await this.call!.balanceOfNFT(nft.contract, account) //case TypeNFT.DRC1155Standart: case TypeNFT.DRC1155: if (tokenId === undefined) throw new Error(`You need to specify the tokenId`) return await this.call!.balanceOfNFT(nft.contract, account, tokenId) default: throw new Error(`The ${typeNFT} type does not exist`) } } public async supportsInterfaceNFT(address: string, interfaceId: string) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) return await this.call!.supportsInterfaceNFT(nft.contract, interfaceId) } public async getRateNFT1155(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.getRateNFT1155(nft.contract, tokenId) } public async calcReserveNFT1155(address: string, tokenId: string | number | bigint, quantity:string | number | bigint) { const rate = await this.getRateNFT1155(address, tokenId) return (BigInt(rate) * BigInt(quantity)).toString() } public async getReserveNFT(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.getReserveNFT(nft.contract, tokenId) } public async getRefundableNFT(address: string) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC721 && typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC721 and DRC1155`); return await this.call!.getRefundableNFT(nft.contract) } public async getSupplyNFT1155(address: string, tokenId: string | number | bigint) { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.getSupplyNFT1155(nft.contract, tokenId) } public async getTokenStakesByMember(account:string) { await this.checkConnect('delegation'); return this.call!.getTokenStakesByMember(account) } public async getTokenStakesPageByMember(account: string, size: string | number | bigint, offset: string | number | bigint) { await this.checkConnect('delegation'); return await this.call!.getTokenStakesPageByMember(account, size, offset) } public async getFrozenStakesQueueToken() { await this.checkConnect('delegation'); return await this.call!.getFrozenStakesQueueToken() } public async getFreezeTimeToken() { await this.checkConnect('delegation'); return await this.call!.getFreezeTimeToken() } public async getStakeToken(validator: string, delegator: string, tokenAddress: string) { await this.checkConnect('delegation'); return await this.call!.getStakeToken(validator, delegator, tokenAddress) } public async getStakeIdToken(validator: string, delegator: string, tokenAddress: string) { await this.checkConnect('delegation'); return await this.call!.getStakeIdToken(validator, delegator, tokenAddress) } // NFT stake view methods (main delegation contract) public async getNFTStake( nftAddress: string, tokenId: string | number | bigint, delegator: string, validator: string, holdTimestamp: number ): Promise { await this.checkConnect('delegation'); return await this.call!.getNFTStakeFromDelegation(nftAddress, BigInt(tokenId), delegator, validator, holdTimestamp); } public async getNFTStakeId( nftAddress: string, tokenId: string | number | bigint, delegator: string, validator: string, holdTimestamp: number ): Promise { await this.checkConnect('delegation'); return await this.call!.getNFTStakeIdFromDelegation(nftAddress, BigInt(tokenId), delegator, validator, holdTimestamp); } public async getAvailableCoinAmount( validator: string, delegator: string, token: string, holdTimestamp: number ): Promise { await this.checkConnect('delegation'); return await this.call!.getAvailableCoinAmount(validator, delegator, token, holdTimestamp); } public async getNFTBackedAmount( validator: string, delegator: string, token: string, holdTimestamp: number ): Promise { await this.checkConnect('delegation'); return await this.call!.getNFTBackedAmount(validator, delegator, token, holdTimestamp); } // Old delegation-nft view methods (deprecated) public async getNFTStakesByMember(account:string) { await this.checkConnect('delegation-nft'); return this.call!.getNFTStakesByMember(account) } public async getNFTStakesPageByMember(account: string, size: string | number | bigint, offset: string | number | bigint) { await this.checkConnect('delegation-nft'); return await this.call!.getNFTStakesPageByMember(account, size, offset) } public async getFrozenStakesQueueNFT() { await this.checkConnect('delegation-nft'); return await this.call!.getFrozenStakesQueueNFT() } public async getFreezeTimeNFT() { await this.checkConnect('delegation-nft'); return await this.call!.getFreezeTimeNFT() } public async getSignPermitDRC721(address: string, spender: string, tokenId: string | number | bigint): Promise { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC721) throw new Error(`Only for DRC721`); return await this.call!.getSignPermitDRC721(nft.contract, spender, tokenId) } public async getSignPermitDRC1155(address: string, spender: string): Promise { await this.checkConnect('nft-center'); const typeNFT: TypeNFT = await this.getNftType(address) const nft = await this.getNFTContract(address, typeNFT) if (typeNFT != TypeNFT.DRC1155) throw new Error(`Only for DRC1155`); return await this.call!.getSignPermitDRC1155(nft.contract, spender) } public async getValidatorStatus(validator: string): Promise { await this.checkConnect('master-validator'); return await this.call!.getValidatorStatus(validator) } public async validatorIsActive(validator: string) { await this.checkConnect('master-validator'); return await this.call!.validatorIsActive(validator) } public async validatorIsMember(validator: string) { await this.checkConnect('master-validator'); return await this.call!.validatorIsMember(validator) } public async getBridgeServiceFees(toChainId: number) { await this.checkConnect('bridge'); return await this.call!.getBridgeV2ServiceFees(toChainId) } //utils public parseEther(amount: string | number | bigint | BigNumberish){ return ethers.utils.parseEther(amount.toString()).toString() } public formatEther(amount: string | number | bigint | BigNumberish){ const amountETH = ethers.utils.formatEther(amount.toString()).toString() const decimals = amountETH.split(".")[1] return decimals == "0" ? amountETH.split(".")[0] : amountETH } public getAddress(address: string){ return ethers.utils.getAddress(address) } public getRandomPassword(count: number, length: number): string[] { const passwords = []; for (let i = 0; i < count; i++) { passwords.push(ethers.utils.hexlify(ethers.utils.randomBytes(length)).slice(2)) } return passwords; } private async getNFTContract(address: string, typeNFT: TypeNFT) { switch (typeNFT as TypeNFT) { //case TypeNFT.DRC721Standart: // return await this.getContract(address) //case TypeNFT.DRC1155Standart: // return await this.getContract(address) case TypeNFT.DRC721: return await this.getContract(address, this.abis?.drc721) case TypeNFT.DRC1155: return await this.getContract(address, this.abis?.drc1155) default: throw new Error(`type ${typeNFT} not exist`) } } public async getDecimalContractAddress(contract: string): Promise { await this.checkConnect(contract); return this.call!.getDecimalContract(contract, true).toString() } public async getDecimalContract(contract: string): Promise { await this.checkConnect(contract); return this.call!.getDecimalContract(contract) } public async getLatestBlock() { const block = await this.provider.getBlock('latest') if (block == null) throw new Error("try again") return block; } public getTokenTypes() { return TokenType; } public async connectToContract(address: string, abi?: ethers.ContractInterface): Promise { return await DecimalContractEVM.getContract(this.network, this.apiUrl, this.account, address, abi) } public async verifyСontract(address: string, contract_code: string, compiler: string, optimizer: string, runs: string, evm_version: string): Promise { return await DecimalContractEVM.verifyСontract(this.apiUrl, address, contract_code, compiler, optimizer, runs, evm_version) } private validationValidatorMeta(meta: ValidatorMeta) { if (meta.commission == undefined || meta.commission == null || meta.consensus_pubkey == undefined || meta.consensus_pubkey == null || meta.description == undefined || meta.description == null || meta.description.details == undefined || meta.description.details == null || meta.description.identity == undefined || meta.description.identity == null || meta.description.moniker == undefined || meta.description.moniker == null || meta.description.security_contact == undefined || meta.description.security_contact == null || meta.description.website == undefined || meta.description.website == null || meta.operator_address == undefined || meta.operator_address == null || meta.reward_address == undefined || meta.reward_address == null ) throw new Error("failed validation of validator meta") } public async getFeeData() { const feeData = await this.provider.getFeeData() if (this.network != NETWORKS.TESTNET) return feeData return { gasPrice: feeData.gasPrice!.add(1), maxFeePerGas: feeData.maxFeePerGas, maxPriorityFeePerGas: feeData.maxPriorityFeePerGas } } //ipfs public async uploadNFTBase64ToIPFS(base64: string, fileName:string, name:string, description:string) { var base64Image; if (base64.includes(';base64,')) { base64Image = base64.split(';base64,').pop(); } else { base64Image = base64; } const buffer = Buffer.from(base64Image!, 'base64'); const blob = new Blob([buffer], { type: base64.split(';base64,')[0].split(':')[1] }) return await this.ipfs.uploadNFTBlobToIPFS(blob, fileName, name, description); } public async uploadNFTBufferToIPFS(buffer:Buffer, fileName:string, name:string, description:string) { return await this.ipfs.uploadNFTBufferToIPFS(buffer, fileName, name, description); } public async uploadTokenBufferToIPFS(buffer:Buffer, fileName:string) { return await this.ipfs.uploadTokenBufferToIPFS(buffer, fileName); } public async getBlobMetadata(name:string, description:string) { return this.ipfs.getBlobMetadata(name, description); } public async uploadNFTFormToIPFS(form: any) { return await this.ipfs.upload(form, true); } public async uploadTokenFormToIPFS(form: any) { return await this.ipfs.upload(form, false); } public getUrlFromCid(cid:string) { return this.ipfs.getUrlFromCid(cid); } }