easyCliPath = $easyCliPath ?? dirname(__DIR__) . '/bin/easycli'; } public function transferFrom(string $fromAddress, string $toAddress, string $tokenExternalId): array { $from = trim($fromAddress); $to = trim($toAddress); $token = trim($tokenExternalId); if ($from === '' || $to === '' || $token === '') { throw new \InvalidArgumentException('Parâmetros inválidos para transferência de token.'); } if (!is_file($this->easyCliPath) || !is_executable($this->easyCliPath)) { throw new \RuntimeException('easycli executable not found or not executable'); } $command = sprintf( '%s token transfer --to %s --token-id %s', escapeshellarg($this->easyCliPath), escapeshellarg($to), escapeshellarg($token) ); $result = BashExecutor::run($command, 120); if (($result['exitCode'] ?? 1) !== 0) { $message = $result['error'] ?: $result['output'] ?: 'Unknown easycli error'; throw new \RuntimeException('easycli transfer failed: ' . $message); } $output = trim((string)($result['output'] ?? '')); $txHash = $this->extractHashFromOutput($output); return [ 'output' => $output, 'error' => trim((string)($result['error'] ?? '')), 'tx_hash' => $txHash, ]; } private function extractHashFromOutput(string $output): ?string { if ($output === '') { return null; } if (preg_match('/0x[a-fA-F0-9]{64}/', $output, $matches)) { return $matches[0]; } return null; } }