Recently we were trying to create an application that allows the user to buy an NFT using an ERC-20 token (let's say for these purposes it's a stablecoin like DAI or USDC). So from figuring everything out we
public async approve(): Promise<void> {
const ticketPrice = 100;
// Approve the contract to transfer on your behalf
const contract = new this.web3js.eth.Contract(TestUSDContract.abi, this.USD_ADDRESS);
const success = await contract.methods.approve('<CONTRACT ADDRESS>', ticketPrice).send({from: '<USER ADDRESS>'});
console.log('Status ' + success);
//Then purchase the item the user wants
const contract2 = new this.web3js.eth.Contract(LotteryContract.abi, this.CONTRACT_ADDRESS);
const value = await contract2.methods.buyItem().send({from: '<USER ADDRESS>'});
console.log('contract2 ' + value);
}
For transparency, the following is the contract method used for testing
function buyTicket() external returns (string memory) {
testUsdContract.transferFrom(msg.sender, address(this), itemAmount);
return "SUCCESS";
}
This all works, however, from a UX perspective, the user gets two dialogs from the UI which seems like bad UX.
Also from what I understand (and makes sense) the approve method MUST be called from the user's account (and cannot be from the contract as msg.sender
on the ERC-20 token will be our contract).
I was wondering what workarounds exists for this AND how other apps accomplish accept ERC-20 items as payment (in a user-friendly manner preferably).
This also begs the question, what happens when the first request is successful and the second fails (could be of network error, or a contract exception), how would one handle that usually in a DAPP (and how have other dapps done this?)