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); $stdout = trim((string)($result['output'] ?? '')); $stderr = trim((string)($result['error'] ?? '')); $combinedOutput = trim(implode("\n", array_filter([$stdout, $stderr]))); if (($result['exitCode'] ?? 1) !== 0) { $message = $combinedOutput !== '' ? $combinedOutput : 'Unknown easycli error'; throw new \RuntimeException('easycli transfer failed: ' . $message); } if ($combinedOutput !== '' && preg_match('/execution\s+reverted/i', $combinedOutput)) { throw new \RuntimeException('easycli transfer failed: ' . $combinedOutput); } $txHash = $this->extractHashFromOutput($combinedOutput); return [ 'output' => $stdout, 'error' => $stderr, '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; } }