I’m using drlecks/simple-web3-php v0.10.0 to transfer USDC on Polygon (contract: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359). I have the sender’s private key and successfully use the library to send USDT with the same approach.
But when sending USDC, the transaction shows up on the blockchain, but:
- No USDC is actually transferred.
- The wallet balance doesn’t change.
- I see two ERC-20 transfer events, one of them has amount 0.
There’s no error returned from the transfer function, but the transfer clearly doesn’t complete properly.
I’m using the same transfer(address,uint256) method, and everything works for USDT. Why would USDC behave differently? How can I fix this using only drlecks/simple-web3-php?
Code snippets :
class Web3
{
private $web3;
public function __construct(private $contractAddress = '', private $contractABI = '', private $chainId = 0, private $transactionId = 0)
{
$productionBaseUrl = 'https://polygon-rpc.com/';
$stagingBaseUrl = 'https://rpc-amoy.polygon.technology/';
$uri = Core::$debug ? $stagingBaseUrl : $productionBaseUrl;
$this->web3 = new SWeb3($uri);
$this->web3->chainId = $this->chainId;
$this->contractABI = html_entity_decode($this->contractABI);
}
public function transfer($address, $privateKey, $amount)
{
$config = $this->config($address, $privateKey);
if ($config->code != 1) {
return $config;
}
$responseConvertValue = $this->convertValue(strval($amount), 'transferUsdt');
if ($responseConvertValue->code != 1) {
return $responseConvertValue;
}
$extraData = [];
if (json_decode($this->web3->personal->getNonce()->value)) {
$extraData = ['nonce' => $this->web3->personal->getNonce()];
} else {
$extraData = ['nonce' => ''];
}
$gasEstimateResult = $this->web3->call('eth_estimateGas', [$extraData]);
if (!isset($gasEstimateResult->result)) {
$this->handleError('transferUsdt', 'Cant get estimateGas');
return (object) ['code' => -3, 'message' => 'Cant get estimateGas'];
}
$extraData['gasPrice'] = $this->web3->getGasPrice();
$extraData['gasLimit'] = $this->web3->utils->hexToBn($gasEstimateResult->result);
try {
$contract = new SWeb3_contract($this->web3, $this->contractAddress, $this->contractABI);
$result =
$contract->send('transfer', [env('MAIN_ADDRESS_WALLET'), $responseConvertValue->value], $extraData);
if (isset($result->error)) {
$message = 'Code :' . $result->error->code . 'Error :' . $result->error->message;
$this->handleError('transferUsdt', $message);
return (object) ['code' => -1, 'message' => $result->error->message];
}
} catch (Throwable $th) {
$this->handleError('transferUsdt', $th->getMessage());
return (object) ['code' => -1, 'message' => $th->getMessage()];
}
return (object) ['code' => 1, 'message' => $result];
}
private function convertValue($value, $methodName)
{
try {
$value = Utils::toWei($value, $methodName == 'transferUsdt' ? "mwei" : 'ether');
} catch (Throwable $th) {
$this->handleError($methodName . ' > convertValue >', $th->getMessage());
return (object) ['code' => -1, 'message' => $th->getMessage()];
}
return (object) ['code' => 1, 'value' => $value];
}
A snippet of a single transmission attempt (https://i.sstatic.net/KPCILlFG.png)