Paying
When an asset is for sale, the first buyer to provide the required amount, in the required currency, will acquire the asset.
As usual, the blockchain determines the order of arrival of payments. In case with race conditions, where multiple transactions for the very same
BuyNowId
arrive, only the first payment is correctly processed, and the rest simply fail.Payments in cryptocurrency are performed by directly transferring funds to a layer-1 smart contract. There are two types of almost identical such contracts:
- prepared to accept only the native cryptocurrency of a layer-1 blockchain,
- prepared to accept ERC20 tokens deployed in of a layer-1 blockchain.
The flow is almost identical for both. The only minor difference is that, in the ERC20 case, every buyer needs to first approve the escrow contract to manage his/her ERC20 tokens. This needs to be done only once in a buyer's lifetime.
Living Assets payments can be integrated by either implementing the API calls described in the sections below, or by simply redirecting users to the Living Assets Payments Gateway.
For a comprehensive understanding of the payment gateway URL's anatomy, please refer to Payments Gateway section.
The first step to pay for an asset in BuyNow mode is to execute this request:
GraphQL
mutation {
createBuyNowPayment(
input: {
buyNowId,
buyerId,
}
)
}
This mutation returns the following data:
PaymentOutput {
paymentUrl,
paymentId,
price,
feeBPS,
universeId,
deadline,
buyerId,
seller,
sellerSig,
}
which is needed in the next step.
To complete the payment, the buyer just needs to provide the funds, alongside the data from the previous query, to the blockchain smart contract.
The
pay
method in the corresponding class of the freeverse-marketsigner-js
library may be used; there is one class for payments in native crypto, and one for ERC20 tokens:Native
ERC20
const { NativeCryptoPayments } = require('freeverse-marketsigner-js');
const { ERC20Payments } = require('freeverse-marketsigner-js');
Checkout examples in both types of currency:
The input parameters provided to the
buyNow
method,paymentsInstance.buyNow({
paymentData,
operatorSignature,
sellerSignature,
from: buyerAddr
})
comprise:
const paymentData =
{
paymentId: PaymentOutput.paymentId,
amount: PaymentOutput.price.toString(),
feeBPS: PaymentOutput.feeBPS,
universeId: PaymentOutput.universeId,
deadline: PaymentOutput.deadline,
buyer: PaymentOutput.buyerId,
seller: PaymentOutput.seller,
}
const operatorSignature = '0x' + PaymentOutput.paymentUrl
const sellerSignature = '0x' + PaymentOutput.sellerSig
As always, make sure to check for enough confirmation blocks before considering the TX confirmed.
Right after the payment is confirmed, the BuyNow is moved to the state
ASSET_TRANSFERING
. Then, after the layer-2 is synchronized with the layer-1, which happens at most within 15 minutes, the asset transfer is settled, and the BuyNow state moves to WITHDRAWABLE_BY_SELLER
.In ERC20 payments, make sure the buyer has approved the escrow contract for managing his/her tokens, as mandatory by the ERC20 standard. The
approve
or approveInfinite
methods provided in paymentsInstance
may be used for this purpose.As before, start with a request:
GraphQL
mutation {
cashoutCrypto(
input: {signature: "${signature}", paymentId: "${paymentId}"}
) {
signature
paymentId
assetTransferSuccess
}
}
The result of the mutation cashoutCrypto is:
type FinalizePaymentOutput {
signature,
paymentId,
assetTransferSuccess
}
which can be used by the seller to call the
finalizeAndWithdraw
method from the corresponding class:JavaScript
paymentsInstance.finalizeAndWithdraw(
{ assetTransferData, signature, from: sellerAddr },
)
where:
JavaScript
const assetTransferData =
{
paymentId: FinalizePaymentOutput.paymentId,
wasSuccessful: FinalizePaymentOutput.assetTransferSuccess,
}
const signature = '0x' + FinalizePaymentOutput.signature
When the TX is confirmed, the BuyNow state moves to
SUCCESS
.In the unlikely event that an asset transfer fails, the smart contract is prepared to refund the buyer. The BuyNow will be moved to state
WITHDRAWABLE_BY_BUYER
, and the refund takes place analogously to the withdrawal process explained above.The cashoutCrypto mutation will return
assetTransferSuccess = false
, and the refund proceeds with the very same call to the finalizeAndWithdraw
method as in the withdrawal case, but with such false
value of assetTransferSuccess
. After a successful refund, the BuyNow will move to the state REFUNDED
.Last modified 4mo ago