How opensea auction smart contract work without storing the ether - ethereum

Trying to understand how opensea "Make the bid" work. Whenever any interested buyer wants to buy an NFT, they have to create an offer,in which they basically sign a message(commitment)(which is not costing gas fees). I didn't understand how this thing works behind the scene. If, let say, i made an offer for 3 days and i won the bid or seller accepted the bid, and i don't have required ether(the bid amount) at that moment, then what will happen?
Auction smart contract basically take bidder amount as stake, and when auction end, if user doen't won the auction, transfer staked ether back, but in both the above process staking ether+paying transaction fees, these extra overhead is there.
Opensea doesn't follow staking of bidding amount and hence save user from paying transaction fees + staking ether. But they ask user to sign for confirmation of bid.
Can anyone explain whats technically happening?
I have gone through below links also but this doesn't answer how opensea is working.
Link 1 : https://ethereum.stackexchange.com/questions/102660/creating-an-auction-smart-contract-without-storing-the-ether
Link 2: https://ethereum.stackexchange.com/questions/110749/auction-data-on-chain-or-off-chain
In link 2, they mention "Commitments are created by signing "messages". These are off-chain transactions. However, cancelling transactions requires posting on-chain." But how is it actually working?

I'll explain how the newest version of Opensea works, called Seaport (docs).
If, let say, i made an offer for 3 days and i won the bid or seller accepted the bid, and i don't have required ether(the bid amount) at that moment, then what will happen?
Simply your offer won't be fulfillable. Opensea's UI should filter unfulfillable offers so they don't get accepted. If an offer is accepted by mistake, nothing bad happens, the transaction simply fails and no token is transferred.
The job of the smart contract is not to store offers, but to verify that an offer is valid and to transfer the tokens accordingly.
It may be a surprise, but the only data stored on the contract are the following mappings
// Track status of each order (validated, cancelled, and fraction filled).
mapping(bytes32 => OrderStatus) private _orderStatus;
// Only orders signed using an offerer's current counter are fulfillable.
mapping(address => uint256) private _counters;
The first mapping ensures that an order can't be fulfilled multiple times or if it was cancelled. (The order is recognized by its bytes32 hash).
The second mapping saves a counter for every offerer. Every offer has a counter parameter that should match _counters[offerer], otherwise it's invalid. This is a smart way to cancel all your existing offers, because you have a "cancel all" function simply increment your _counters.
This should have answered why to cancel orders you need to have a on-chain transaction. Because nothing guarantees that an offer is forgotten by everyone off-chain.
Opensea doesn't follow staking of bidding amount and hence save user from paying transaction fees + staking ether. But they ask user to sign for confirmation of bid. Can anyone explain whats technically happening?
The "confirmation of bid" is a wallet signature (EIP-712) necessary to make the process trustless. No one will be able to steal tokens by forging offers. The only trusting assumption is that Opensea won't hide an offer from a buyer/seller.

Related

Stuck with deciding the working of a Smart Contract Project

So I'm doing a project which basically carries out the medical insurance claim process with the help of the smart contract. How it works is:
User signs up to the website run by the insurer.
They file a claim by entering the concerned hospital, insured amount and a pdf file containing the bills which are to be verified.
The hospital uses the website to approve/deny the claim based on the info provided.
The insurer uses the website approve/deny the claim based on the info provided and pays the user.
Any time someone files, approves/denies, pays the claim, an event is emitted.
This is my first ethereum/solidity project and I'm unable to figure out how to pull this together.
This is the structure of a Claim:
struct Record {
uint id; // unique id for the record
address patientAddr;
address hospitalAddr;
string billId; // points to the pdf stored somewhere
uint amount;
mapping (address => RecordStatus) status; // status of the record
bool isValid; // variable to check if record has already been created or not
}
Some of my questions were:
How do I link a Record to a specific user? As a single user can use multiple Metamask wallets.
Is it possible to fetch all the events linked to a specific record with an id so I can display all the approvals/denials happened with the Record to the user?
For the hospital, is there a better way to get associated Records other than to get all Records from the smart contract and then filter it on the front end?
Thanks a lot for your help.
To link a Record to specific user you will need to add a mapping (I am assuming that you have a user ID) that will look like this:
mapping(uint => Record[]) recordsByUserID;
Then you will be able to get an array of Records knowing the user id by:
Records userRecords[] = recordsByUserID[user_id];
About the event logging it's actually kind of easy because we have the indexed keyword, let me show you an example:
event Approved(uint indexed userId, uint indexed recordId);
With an event like this you are able to query all the events using the user id and the record id.
About the third question I suggest you to use the graph https://thegraph.com/en/. It basically creates your own GraphQL backend by indexing all the events for you in a very easy way. Then you are able to run your graphql queries and make something efficient.

How price in Uniswap and PancakeSwap is formed

I am creating an exchange similar to pancakeswap with limited features like exchange and liquidity only.
I am using the Pancake router contract code https://testnet.bscscan.com/address/0xd99d1c33f9fc3444f8101754abc46c52416550d1.
We are giving the price at the time of creating pair for our token with BNB by adding liquidity by calling addLiquidityETH function in router contract. Its working and creating pair. Then the value is fixed for that pair.
Having some doubts.
What is that value?
If the price of the BNB Increases in market. How can we fetch the current market price and update in our own DEX?
Is this contract will do this or we have to call any other API providing API....
I gonethrough the https://uniswap.org/docs/v2. But I didnt find the solution for above queries
Then the value is fixed for that pair
You cannot fix value at open markets.
What is that value?
You can find out about price formation in Uniswap v2 and other bonding curve exchange here. Essentially, value is set by buyers and sellers, depending on how much they buy or sell.
If the price of the BNB Increases in market. How can we fetch the current market price and update in our own DEX?
You cannot, because the value is set by buyers and sellers. You need become buyer and seller and spend money to set the price, effectively market make your token pair.
Is this contract will do this or we have to call any other API providing API
Does not make to discuss this, as your earlier assumptions are incorrect.

What happens if someone ask while a transaction is happening?

Am reading this tutorial about transactions, however, I have some doubts about it and can't find an answer.
Lets supose a system where the server (back-end) has this scenario to borrow money to someone (user account A borrows money to user account B):
1. Ask to Database the money of user account A
2. Check in the server if it is enough to complete the payment
3. Make a stereotypical transaction for that in the Database
After this, user account A runs out of money.
However, like the article mentions, if user A shares the account with user C, and user C try to make the same operation (borrow to B), at the same time, in the first step (retrieve money from the database of user account C, which is the same as user account A), this query will answer with the previous value. Thus it will have enough money to make this transaction.
Is my approach correct?
How could I fix this? Would I need an internal proccedure?
Thank you.

Getting each wallet address balance

I’m currently having a hard time figuring how to get to check users wallet addresses and get the balances ie if a user wants to send out 3Eth and they have like 10 addresses with different amounts inside them, how do I subtract the amount from each address to get the 3Eth the user wants to send out?
In Ethereum (unlike Bitcoin), each transaction can only have one from address. So to transfer ether from n addresses, you'll need n transactions.

Data duplication between internal database and Solidity

There is a flow I want to achieve in my dapp, and I would appreciate some opinion.
Flow:
User sees a list of products and picks one to buy it. The user has their metamask unlocked and has enough balance.
Setup:
Rails on the backend, React on the frontend, ganache-cli, truffle, metamask (web3js).
Database structure:
In the app's internal PostgresDB, there's a products table. In the blockchain, there's a dynamic array products like below:
Internal Postgres:
products
name
price
owner_id
owners
name
id
address
Blockchain (contract storage)
Product[] products
struct Product {
name
}
mapping(uint => address) public productIdToOwner;
mapping(uint => uint) public productIdToPrice;
The following function onBuy runs when the user clicks "Buy this product" button:
onBuy = (product) => {
const { id, external_id, name, price, meta } = product
this.ContractInstance.methods.buy(external_id).send({
from: this.state.currentUserAddress,
gas: GAS_LIMIT,
value: web3.utils.toWei(price.toString(), "ether"),
}).then((receipt) => {
// What to do before getting a receipt?
console.log(receipt)
}).catch((err) => {
console.log(err.message)
})
}
Questions:
On the mainnet, how long does it take for me to get the receipt for the transaction? Is it sane to make the user wait on the same page after clicking the onBuy button with a loading wheel until the receipt arrives? If not, what's the conventional way to deal with this?
Is my DB structure a reasonable way to connect to the blockchain? I am worried about data integrity (i.e. having to sync address field between my internal DB and the blockchain) but I find it useful to store the blockchain data inside the internal DB, and read mostly from the internal DB instead of the blockchain.
On the mainnet, how long does it take for me to get the receipt for the transaction? Is it sane to make the user wait on the same page after clicking the onBuy button with a loading wheel until the receipt arrives? If not, what's the conventional way to deal with this?
When you send a transaction, you will get the transaction hash pretty quickly. However, the receipt is only returned once the transaction is mined. The length of time it takes to have your transaction mined varies greatly depending on how much you're willing to pay for gas (can be several seconds for very high gas prices or can be several hours if you're paying < 10 Gwei). You can get an idea by using Ropsten/Rinkeby (the test networks will probably be faster than MainNet). Chances are (and based on the system you're describing), it won't be reasonable to have your user wait.
I don't know if there is a "conventional" way to deal with this. You can provide the user with your own confirmation number (or use the transaction hash as the confirmation number), send an email when the transaction is mined, push a notification if on a mobile app, etc. If you present the user with some sort of confirmation number based on the transaction hash, you'll have to decide how you want to resolve cases when the transaction fails.
Is my DB structure a reasonable way to connect to the blockchain? I am worried about data integrity (i.e. having to sync address field between my internal DB and the blockchain) but I find it useful to store the blockchain data inside the internal DB, and read mostly from the internal DB instead of the blockchain.
This is purely an opinion, so take this with a grain of salt. I try to avoid having duplicate data, but if you're going to have multiple persistence layers you'll probably need to maintain some sort of referential integrity between them. So, it's certainly ok to store ids and addresses.
The part of your question that confuses me is why do you prefer to read mostly from the DB? Have you tried measuring the latency of using a fully sync'ed node on your server and retrieving data from your contract through constant functions? I would test that first before duplicating my data. In your case, I would look to use the blockchain to store purchases while using the DB just for inventory management. But, that's based on very little knowledge of you business case.