Introduction

With this tool a merchant can accept payments through a smart contract using liquidity pools. Smart contract for merchant creates 0xProcessing.
Web3 processing allows clients to pay with Web3 wallets in any of the available iterations: either with a widget on the website or a mobile wallet.
In this case, the size of the liquidity pool, the number of transactions and their volume, as well as any other necessary information that you would like to broadcast, can be available to users in real time through the blockchain browser or frontend of your website.
In addition, the functionality of Web3 processing allows you to set up automatic payouts to your employees' Web3 wallets.
Before you start integrating the method, leave a support request to activate the appropriate functionality. This deposit method supports BNB chains.
First, you need to contact technical support to connect your merchant to this feature. After receiving an answer from technical support about readiness, you can start the integration.

API endpoint: https://web30.0xprocessing.com/

To authorize in the API you need to generate a token in your personal account under "Settings - Merchant Management - Web3 API Token".
Requests must contain the APIKEY header with your API key.

The process of adding tokens to the whitelist

In order for the liquidity pool to accept the tokens you want, you must add them to the whitelist of the smart contract.
First, you need to select from the available tokens the ones you need to work with.
You can see the list of supported tokens in the method Info/SupportedTokens.
You can add tokens in the method ContractSettings/AddTokenToWhitelist.
All methods of interaction with the contract return the id of the request, the status of which can be viewed in the method Queue/Status/{requestId}
After executing the request, be sure to verify that the request has been successfully executed.

Depositing tokens into the pool by users

To deposit a token into the pool, you must create a "Deposit" button in the user environment.
Example: token_contract_address – token contract address (can be obtained from the method Info/SupportedTokens) pool_contract_address – address of the pool contract (can be obtained from the method Info/Contract)
HTML:
<button id="0xWeb3PoolConnectButton">Connect MetaMask</button>
<div id="0xWeb3PoolDepositSection" style="display: none">
<input type="number" min="0" step="any" id="0xWeb3PoolDepositInput" placeholder="Amount" />
<button data-token="{token_contract_address}" data-pool="{pool_contract_address}" id="0xWeb3PoolDepositButton">Deposit</button>
</div>
JS:
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.7.0-rc.0/web3.min.js"></script>
<script>
//Connect Metamask
window.addEventListener('load',
async () => {
if (window.ethereum) {
window.web3 = new window.Web3(window.ethereum);
initConnectButton();
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
initConnectButton();
}
});
//Initializing the connection button
const initConnectButton = async () => {
web3.eth.getAccounts(function(err, accounts) {
if (err != null) {
document.getElementById('0xWeb3PoolConnectButton').style.display = 'none';
}
});
document.getElementById('0xWeb3PoolConnectButton').addEventListener('click',
async () => {
if (window.ethereum) {
try {
await window.ethereum.request({ method: 'eth_requestAccounts' });
initPayButton();
} catch (err) {
console.log('User denied access', err);
}
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
initPayButton();
}
});
}
//Initialization of the payment button
const initPayButton = () => {
document.getElementById('0xWeb3PoolConnectButton').style.display = 'none';
document.getElementById('0xWeb3PoolDepositSection').style.display = 'block';
document.getElementById('0xWeb3PoolDepositButton').addEventListener('click',
async () => {
var accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
web3.eth.defaultAccount = accounts[0];
const contractAbi = JSON.parse('[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"_decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]');
//Token contract address
var tokenAddress = document.getElementById('0xWeb3PoolDepositButton').dataset.token;
//Obtaining the object of the contract
const contract = new web3.eth.Contract(contractAbi, tokenAddress);
//Address of the pool for the deposit
var to = document.getElementById('0xWeb3PoolDepositButton').dataset.pool;
//Deposit amount
var amount = document.getElementById('0xWeb3PoolDepositInput').value;
const decimals = web3.utils.toBN(18);
var value = amount * Math.pow(10, decimals);
//Calling the transfer contract method
contract.methods.transfer(to, web3.utils.toHex(value)).send({ from: accounts[0] },
function(error, result) {
if (!error) {
//Transaction result processing
console.log(result);
} else {
//Transaction error processing
console.log(error);
}
});
});
}
</script>

Webhook

All deposits are tracked by the system and you can get a callback on a user's successful deposit into the pool.
The report of the deposit is implemented by means of webhooks.
You need to configure the webhook in your Merchant’s account in the section "Merchant\ Web3 processing\Webhook URL". Required https (TLS/SSL)
WebHook password - password required to check the signature.
Parameters:
Name
Description
Type
Id
Transaction Id
integer
From
Sender's address
string
To
Recipient's address
string
Amount
Amount
double
Currency
Currency
string
Hash
Transaction Hash
string
Type
Transaction type: claim, deposit, withdraw
string
Signature
Checksum, to verify the authenticity of the request
string
Signature Check:
1. A string of the following form must be generated: "Id":"Currency":"Hash":"From":"Password" (Without quotation marks through a colon)
2. Encrypt the resulting string using the MD5 algorithm
3. Compare the resulting string with the one that came through Webhook
4. If the strings match, you should return HTTP Status 200 (Required)
Example Webhook JSON:
{
"Id":19851,
"From":"0x000000.....",
"To":"0x000000.....",
"Amount":10.00264765,
"Currency":"BNB",
"Hash":"0x000000.....",
"Type": "claim",
"Signature":"a5510c8c3e657ffd8229813749cd20ec"
}

Claim

To allow a user to claim tokens from the pool (withdrawal), it is necessary to reserve an amount for that user in the contract, as well as provide the user with a Claim button.
To reserve the required amount for a certain user, you need to call the method Claim/AddUserClaimable.
During the reservation, the commission of the pool will be withdrawn.You can find this information on the form Info/Contract.
After successfully reserving an amount, the user can "claim" it from the contract via claim.
In order for the user to pick up his tokens, it is necessary to call the method Claim of the contract.
Example button: HTML:
<div id="0xWeb3PoolClaimSection" style="display: none">
<p>Available: <span id="0xWeb3PoolClaimAvailable"></span></p>
<input type="number" min="0" step="any" id="0xWeb3PoolClaimInput" placeholder="Amount" />
<button data-token="{token_contract_address}" data-pool="{pool_contract_address}" id="0xWeb3PoolClaimButton">Claim</button>
</div>
JS:
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.7.0-rc.0/web3.min.js"></script>
<script>
window.addEventListener('load',
// Connecting Metamask
async () => {
if (window.ethereum) {
window.web3 = new window.Web3(window.ethereum);
initConnectButton();
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
initConnectButton();
}
});
const initConnectButton = async () => {
web3.eth.getAccounts(function(err, accounts) {
if (err != null) {
document.getElementById('0xWeb3PoolConnectButton').style.display = 'none';
}
});
document.getElementById('0xWeb3PoolConnectButton').addEventListener('click',
async () => {
if (window.ethereum) {
try {
await window.ethereum.request({ method: 'eth_requestAccounts' });
initClaimButton();
} catch (err) {
console.log('User denied access', err);
}
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
initClaimButton();
}
});
}
const initClaimButton = async () => {
document.getElementById('0xWeb3PoolConnectButton').style.display = 'none';
document.getElementById('0xWeb3PoolClaimSection').style.display = 'block';
const contractAbi = JSON.parse('[{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"inputs":[{"internalType":"address","name":"recepient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addUserClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPercent","type":"uint256"}],"name":"feePercentChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecepient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recepient","type":"address"}],"name":"feeRecepientChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reserved","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"whitelistERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recepient","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawalAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"}]');
var accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
web3.eth.defaultAccount = accounts[0];
var tokenAddress = document.getElementById('0xWeb3PoolClaimButton').dataset.token;
var poolAddress = document.getElementById('0xWeb3PoolClaimButton').dataset.pool;
var contract = new web3.eth.Contract(contractAbi, poolAddress);
var decimals = web3.utils.toBN(18);
contract.methods.claimable(accounts[0], tokenAddress).call(function(error, result) {
document.getElementById('0xWeb3PoolClaimAvailable').innerHTML = result / Math.pow(10, decimals);
});
document.getElementById('0xWeb3PoolClaimButton').addEventListener('click',
async () => {
var amount = document.getElementById('0xWeb3PoolClaimInput').value;
var value = amount * Math.pow(10, decimals);
console.log(value);
contract.methods.claim(web3.utils.toHex(value), tokenAddress).send({ from: accounts[0] },
function (error, result) {
if (!error) {
console.log(result);
} else {
console.log(error);
}
});
});
}
</script>
The result of the claim procedure, that is, when the user received tokens from the contract to his wallet can be received in the same way as a deposit.

Withdraw

Withdraw the balance of tokens from the contract (except those reserved for users).
Withdrawal of free tokens is performed using the method /Withdraw
The number of available free tokens can be obtained by the method /Contract/Info