BD Flashcards

(167 cards)

1
Q

The difference between –save and –save-dev is

A

–save gets added to the dependencies and –save-dev gets added to devDependencies which is libraries you only need for your development environment

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

The Zsh equivalent of .bash_profile is

A

.zshenv

note: Zsh does not source .bash_profile, .bashrc

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

The first line in a solidity contract is

A

pragma solidity >=0.7.0 <0.9.0;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Contract names are written in

A

contract CapitalCase

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

To write a getter function in solidity, type

A

function get() public view returns(string) {
return var_name;
}

or

string public varName;

Note: Setters are not generated, only getters for public/external top level variables

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Variable names are written in

A

camelCase

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

The 4 contract memory locations are

A

storage, memory, stack, calldata

storage: stored in the blockchain
memory: stored in memory and disappears after function runs, can be passed to other functions
stack: a variable that only exists inside a function and ceases to exist after function runs. A plain variable declaration in a function is automatically stored in stack.
calldata: Must be used for arguments to functions that are public or external. Like, literally data from a call.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

To create an array, type

A

type[10]

arrays in solidity must all have the same type

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

To create a variable for an ethereum address type

A

address varName = “string”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Top level variables that have no memory location tag are automatically saved to

A

storage

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

To write a setter function in solidity, type

A

function set(string _paramName) external {
varName = _paramName;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

The 4 function visibility keywords are

A

private: Only the smart contract can call the function (use underscore on func name as convention)
internal: Only the smart contract can call the function or the smart contract that inherited this function
external: Can only be called from outside the smart contract
public: Can be called from inside and outside the contract

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

The 4 function visibility keywords are

A

private, internal, external, public

private: Only the smart contract can call the function (use underscore on func name as convention)
internal: Only the smart contract can call the function or the smart contract inherited this function
external: Can only be called from outside the smart contract
public: Can be called from inside and outside the contract

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Variables with no visibility keyword default to

A

private

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Remix will not let me deploy without starting with

A

// SPDX-License-Identifier: GPL-3.0

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

People can only run your smart contract’s functions on ether scan if you

A

upload your source code

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

An interface is

A

A group of function signatures (everything before the curly braces) that match ones present in a different contract. You define them in order to be able to call that remote contract’s functions in your own contract.

Each interface only connects to one contract.

interface MyInterface {
function remoteFunc() external view returns (uint);
}

Then to call the remote function in my contract, type

MyInterface(remoteContractAddress).remoteFunc();

Note: For some reason, interface functions must be external even though the original function might be public and it still works.
I do not need to copy the virtual/override from the signature.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

msg.sender is

A

the address of the person or contract calling your function. The msg variable is global.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

msg.value is

A

the amount of gwei being sent to your contract from the person calling your function.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

The difference between tx.origin and msg.sender is

A

tx.origin is the original person to initiate a transaction and msg.sender can be an intermediate contract triggered by the original person.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

To throw an error if a value is negative, type

A

require(false, “Error message”)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

To send ether to an address, type

A

(bool success, ) = address(“address”).call{value: 1 ether}(“”);
require(success);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

For a smart contract to receive ether, it must have at least one function with

A

a payable tag

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

To make your contract able to receive ether, add the function

A

receive() external payable { … }

Or make any function payable, but that might require the sender to call it in a more sophisticated way (like in a UI or using an interface), rather than simple send from any wallet.

note: Contracts can only have one receive function

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
The fallback() function is called when someone
calls a contract with non empty calldata but no other function matches
26
To make an array of payable addresses, type
address payable[] public arrayVar
27
To set the owner of a contract to the person that deploys it, type
address owner; address param; constructor(string passedInParam) { // initialize the owner on deployment owner = msg.sender; param = passedInParam; } Note: Useful for when you need one person to be able to run important functions. You need to initialize the empty variables above the constructor before it updates them.
28
To cast a msg.sender address into a payable address, type
payable(msg.sender)
29
To add to an array at the end, type
arrayName.push(itemName)
30
To get the balance of your own smart contract, type
address(this).balance
31
To remove all the elements of an array, type
delete arrayName
32
If variables are declared outside a function, changing them inside a function will still
update the storage on the blockchain
33
The protocol id for NFTs is
ERC-721
34
To inherit the functions and variables from a parent contract, type
contract ChildContract is ParentContract { }
35
To pass an argument to the constructor function of a parent contract, type
constructor() public ParentContractName("param_1") { ... }
36
To inherit multiple contracts, type
contract ChildContract is ParentContract1, ParentContract2 { ... } If multiple parents have the same function, the last in the list overrides the previous. The convention is to order from most base to most derived.
37
To inherit multiple contracts, type
contract ChildContract is ParentContract1, ParentContract2 { ... } If multiple parents have the same function, the last in the list overrides the previous
38
The difference between a contract that is basic vs derived
derived inherits from more contracts
39
To create an event, type
event EventName(type varName, type varName) Note: using "indexed" makes that field filterable, but its expensive. to emit an event, type emit EventName(varName,varName)
40
To allow external consumers to filter out events based on the value on one of the fields, type
event EventName(type indexed varName, type varName) Only 3 fields can have indexed.
41
Events cannot be read by
smart contracts. They are read by listeners using web3/ethers.
42
Use the storage memory location if you need
the variable change to persist after the function ends/create a transaction. It writes to the blockchain.
43
To set unique permissions on a function use
require() at the beginning of it so the function errors if the expression is false
44
A good way to model people into a variable is
struct Person { uint height; bool alive; address friend; } mapping(address => Person) public people;
45
To create a modifier that only allows the owner to run a function, type
modifier onlyOwner() { require(owner == msg.sender, "Ownable: caller is not the owner"); _; } import "@openzeppelin/contracts/access/Ownable.sol"; contract MyContract is Ownable { function myFunc() public onlyOwner {} }
46
To map an NFT to an owner, type
mapping(uint256 => address) private _owners; Dom did it like this: // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex;
47
You cannot know what NFTs an address holds because
there is no index to search. You would either have to use a function in the smart contract that maps an owner address to an NFT id, or set up a listener for Transfer events that constantly updates your database.
48
To verify a user has the key to a wallet, you essentially need to
create a random nonce, have them sign it with metamask. Cryptokitties has the correct workflow.
49
Metamask automatically injects
an object called ethereum that you can call functions on to do stuff
50
To see a user's wallet addresses using metamask, type
ethereum.request({ method: 'eth_requestAccounts' }).then(data => console.log(data))
51
To sign a message using metamask, type
Note: In order use this, you must first use 'eth_requestAccounts' var from = "0xf7c3abd77184cdbc9417890820b3ffcfe4bcd333" var msg = "Hi there" // Prob need to cast to hex var params = [msg, from] var method = 'personal_sign' ethereum.request({method, params}).then(data => console.log(data)) or ethereum.request({method, params, from}).then(data => console.log(data)) After I sign into cryptokitties, they send my wallet address and my encrypted message to their server and their server sends me back another token. If I can successfully extract their real wallet address from the signed message just using the initial message and the token, then it means they successfully signed it with their secret. For some reason crypto kitties sends back a token and saves it under a tokens cookie after my wallet address. "To summarize this block, what it does is, given our msg (containing the nonce) and our signature, the ecrecover function outputs the public address used to sign the msg. If it matches our publicAddress from the request body, then the user who made the request successfully proved their ownership of publicAddress. We consider them authenticated." This explains the backend decently. https://www.toptal.com/ethereum/one-click-login-flows-a-metamask-tutorial#lets-build-it-together This post shows the steps necessary to get public address from signed message https://ethereum.stackexchange.com/questions/12571/getting-an-address-from-ethereumjs-utils-ecrecover ethereumJSUtils works in node https://github.com/ethereumjs/ethereumjs-util Closest solution https://ethereum.stackexchange.com/questions/35486/how-to-verify-metamask-account-holder-is-the-real-owner-of-the-address?noredirect=1&lq=1 https://ethereum.stackexchange.com/questions/35486/how-to-verify-metamask-account-holder-is-the-real-owner-of-the-address https://ethereum.stackexchange.com/questions/54715/metamask-verification-on-a-server-with-web3-personal-sign?noredirect=1&lq=1 https://github.com/danfinlay/js-eth-personal-sign-examples/blob/master/index.js
52
How synthetic loot works is basically
it uses your wallet address as a seed to deterministically choose all the items. If you make a ton of wallets, then it will make a ton of loots.
53
Adding the --global tag to npm install makes
makes the package available in any shell and not just inside the current project
54
npm only manages
server side packages. Not front end. There are other front end package managers. It's called NODE package manager.
55
To signal the intent that a function can be overridden by a contract that inherits it
add the modifier "virtual" function myFunc() virtual public returns(uint) {...}
56
To run the scripts with async functions in hardhat reliably, people usually
use an async function and then put await before all async calls
57
To control a contract using ethers, type
Ethers always expects you to give it and returns BigNumbers instead of regular js numbers. eg ethers.BigNumber.from(5) To pass values to a contract constructor deployed by ethers add as arguments to the deploy function. Ethers.js returns the transaction data instead of the contract function return value, if the function requires creating a transaction. This means if I want to get the return, I'll need to set it to a function and then create a getter function. To deploy a contract const contractTemplate = await ethers.getContractFactory("Token") const myDeployedContract = await contractTemplate.deploy() await myDeployedContract.deployed() then you can use myDeployedContract.address await myDeployedContract.contractFunction() Note: Contracts must have an owner. Ethers automatically uses the first signer from const [owner] = await ethers.getSigners() as the owner. It is best to call that ourselves as well so we can have access to it. To call a contract function from a different address than owner, type const [owner, addr1, addr2] = await ethers.getSigners() await myDeployedContract.connect(addr1).contractFunction() To explicitly choose the address of the signer, type accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); provider = new ethers.providers.Web3Provider(window.ethereum); signer = provider.getSigner(accounts[0]); To create a signer, type new ethers.Wallet(private_key, optional_provider) To call a payable function, you need to add as a third argument overrides = { // To convert Ether to Wei: value: ethers.utils.parseEther("1.0") // ether in this case MUST be a string // Or you can use Wei directly if you have that: // value: someBigNumber // value: 1234 // Note that using JavaScript numbers requires they are less than Number.MAX_SAFE_INTEGER // value: "1234567890" // value: "0x1234" // Or, promises are also supported: // value: provider.getBalance(addr) }; await MintingPress.mintToken(1, overrides) To return a public variables in ethers, just call the exact variable name as a function To create an event listener in ethers, type filter = { address: dwede, // Omit to listen to all addresses topics: [ utils.id("Transfer(address,address,uint256)"), ] } provider.on(filter, (data) => { ... }) in hardhat, ethers is added to the global scope in the scripts folder, so you dont need to instantiate it, it instantiates based on your default config or the flags you add when running a script. In ethers a provider can x while a signer can y providers can read a smart contract signers (have access to private key) so can create transactions aka write to blockchain To use ethers to interact with a contract on a testnet or mainnet, you need to put the script inside scripts folder and run hh run scripts/script.js --network network-name and it already has your ethers object set up. It seems that in hardhard, getting a instantiating a signer uses the api in the config for the wallet, but getting a provider you need pass in your api info during instantiation.
58
You can guess which javascript functions will take a long time by
asking if this action is probably going to take a long time to complete
59
You must use "await" if the function you are calling
returns a promise
60
To add OpenZeppelin to hardhat, type
npm install --save-dev @openzeppelin/contracts
61
An abstract class is
a base class that you can inherit into a child class but contains functions that are declared but have no body that you will be forced to override them in order to instantiate the child class.
62
To override a virtual function, type
function myFunc() public override(ContractName) {}
63
A modifier is
A function that you add after your visibility keyword that will run before your function. A modifier can access the parameters passed into the main function by using parentheses. myModifier(paramName) You can use multiple modifiers and they will run in sequence. To create a modifier type modifier myModifer() { // do something _; } The underscore in modifiers represents calls the main function or the next modifier in the chain of there is one. https://youtu.be/RobaQulUzsY
64
The basic signature of a function is
function functionNams(type paramName, type paramName) visibility modifier modifier returns(type) {}
65
To return multiple values from one function, type
function multiFunc() visibility modifier returns(type, type) { return(valueOne, valueTwo); } And to assign each returned value, type variableOne, variableTwo := multiFunc()
66
For struct, array and mapping types, it is mandatory to Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return variables.
write the explicit data location keyword including for function params and return variables. uint[] storage myArray; function myFunc(uint[] memory myArray) visibility modifier returns(uint[] memory) {}
67
Functions that can be called by external parties must
explicitly use calldata as the memory location of the function parameters function myExternalFunc(string calldata paramOne) visibility modifier {}
68
To call a function from an inherited class that you overwrote in you child class, type
super.functionName()
69
If a function has both virtual and override as modifiers it means
It is overriding a function with the same signature in a parent contract by using override, and it is also allowing you to override it in you contract by using virtual.
70
The virtual modifier tells the user that
the function is allowed to be overridden after you inherit it by using function sameFunc(type sameParam) visibility override {}
71
An OpenZeppelin hook is
simply a function they added to their contracts that runs before other functions that you can override in your child function in order to add functionality into their call sequences. Rules: Always re-apply the virtual attribute to the hook. That will allow child contracts to add more functionality to the hook. Always call the parent’s hook in your override function using super to continue the call sequence. This will make sure all hooks in the inheritance tree are called: contracts like ERC20Pausable rely on this behavior. contract MyToken is ERC20 { function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override // Add virtual here! { super._beforeTokenTransfer(from, to, amount); // Call parent hook ... } }
72
A token contract is basically
a mapping of addresses to balances, plus some methods to add and subtract from those balances.
73
Transferring an nft is basically
changing the address mapped to the id of an NFT. Opensea is able to handle transfers by calling contracts that comply with ERC721 standard and asking the user to use metamask in order to sign the transaction to prove ownership.
74
The way dom implements a random list item plucker is
uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId)))); string memory output = sourceArray[rand % sourceArray.length];
75
Opensea is basically
a UI for people to use metamask/ethers.js to call functions on contracts that comply with ERC721 which have a tokenId to address mapping.
76
To make a ternary operator in solidity, type
1 > 0 ? true : false
77
ERC721 tokens keep a mapping of
tokenIds to ownerAddresses and also ownerAddresses and total number of NFTs.
78
The purpose of pinning a file on pinata is to
make the IPFS filed you uploaded available even when your local daemon is down.
79
JS cheat sheet javascript
The document loaded event doesn't fire until all images are loaded. To read from file system synchronously in node, type const fs = require("fs").promises; fs.readFile("/...") etc Then use all the old names const fs = require("fs"); function range(start, stop, step) { if (typeof stop == 'undefined') { // one param defined stop = start; start = 0; } if (typeof step == 'undefined') { step = 1; } if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) { return []; } var result = []; for (var i = start; step > 0 ? i < stop : i > stop; i += step) { result.push(i); } return result; }; range(5).forEach(i => { }) fs.writeFileSync( contractsDir + "/contract-address.json", JSON.stringify(metadataObj) ); if you are exporting a function, you can still import a dependency from outside of the function https://stackoverflow.com/questions/27008999/scope-of-dependencies-when-exporting-a-module-in-node-js To import a file using require, type const utils = require("./utils"); To import one function from a file using require, type const funcName = require("./utils").funcName To read and write json JSON.stringify() JSON.parse() To get node script argument from command line, type const args = process.argv.slice(2) console.log(args[0]) To check if a value is undefined and throw an error, type if (arg !== undefined) { } In js, not providing 2 arguments to .replace() causes the second argument to become undefined. Note: Use replaceAll() for replacing all (only in browser, not supported by node) It seems that if you make a function async, you maybe use await when calling it, not just inside it. To check if a value is in an array, type myArray.includes("value")) you cannot use await inside a forEach loop, because each iteration's execution is asynchronous. forEach mutates the original array, while map just creates a new object you'll need to assign.
80
To install a plugin into hardhat the two steps are
npm install it add to hardhat.config.js require(""@nomiclabs/plugin-name"")
81
One way to start a Token contract's reserves is with
all the tokens belonging to the owner and having transfer functions uint256 public totalSupply = 1000000; address public owner; mapping(address => uint256) balances; constructor() { The totalSupply is assigned to transaction sender, which is the account balances[msg.sender] = totalSupply; owner = msg.sender; }
82
the ABI is
the compiled version of your high level code that the machine code can execute.
83
When you run hh compile, hardhat
compiled all your contracts into ABIs and saves the ABIs into the artifacts folder.
84
To assert equality in chai, type
expect(true).to.equal(true);
85
The proper structure for mocha tests (like presetting variables) is set out here
https://hardhat.org/tutorial/testing-contracts.html#full-coverage
86
The reason to use ERC721Enumerable is
it provides a totalSupply method
87
To concatenate 2 strings, type
abi.encodePacked("string", "string")
88
Reentrancyguard prevents
a contract from calling itself import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; Inherit the ReentrancyGuard class Then add the nonReentrant modifier to a function that is doing something important.
89
OpenZeppelin tells you which methods you need to implement yourself by
including them in the IERC file by the same name with no body. e.g. ERC721, and IERC721 Note: It also injects fully implemented events this way.
90
To convert a BigNumber balance from a smart contract to a readable number, type
ethers.BigNumber.from(await contract.totalSupply()).toNumber() or ethers.utils.formatEther(await contract.balance)
91
To run scripts in hardhat, type
hh run scripts/script.js
92
To deploy my smart contract to an external network, you need to
Create an account on alchemy, get your api link and add it to networks in hardhat.config.js networks: { rinkeby: { url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_API_KEY}`, accounts: [`0x${RINKEBY_PRIVATE_KEY}`], } To get some free eth for the test account In metamask create a new address in the rinkeby network Post the address on twitter Post that into a faucet, which will send you ether export your private key from metamask and add to hardhat config https://www.youtube.com/watch?v=Uvphp4aVeDg Run the deploy script hh run scripts/deploy.js --network network-name You can then see it on rinkeby.etherscan.io using the returned address
93
IPFS sheet
To run an IPFS daemon, type ipfs daemon To download a file hosted in IPFS, type (while daemons on) ipfs cat /ipfs/QmSgvgwxZGaBLxsYLKtdy3vGZ8uq > ~/Desktop/name.jpg The target url for files hosted on IPFS is https://ipfs.io/ipfs/QmXKnygUEzRVVs or https://gateway.ipfs.io/ipfs/QmXKnygUEzRVVs And for local it is http://127.0.0.1:8080/ipfs/09ed8jf2390irdf0reid To view the local dashboard ui go to localhost:5001/webui The IPFS Companion chrome extension allows you to open IPFS links in chrome by querying the local daemon running. This IPFS api wrapper can connect to your local daemon and add files to it https://github.com/ipfs/js-ipfs/tree/master/packages/ipfs-http-client#example IPFS does not propogate the files you add to it, it just makes it accessible from your node to other nodes. If another node requests it it will storage a copy temporarily.
94
To make a directory path, type
const path = require('path'); const directoryPath = path.join(__dirname, '../images'); Note: __dirname is the path to the current script path.join("a", "b") become "a/b"
95
Remember to make javasrcript
very functional
96
ENS is basically
There is a smart contract that auctions off names When someone wins an auction, their name gets added to a mapping (aka registry) of that name to an address of a different smart contract that the auction winner owns (called a resolver) The resolver contract can be updated to forward transactions to wherever the owner wants (like their metamask wallet) The resolver contract has a variable called content that can contain an IPFS hash so your ENS name can open that site if you type it into a browser that resolves ENS names (brave) or you can use Name.eth.link as a gateway in other browsers. https://towardsdatascience.com/decentralizing-your-website-f5bca765f9ed https://medium.com/xord/ethereum-name-service-ens-how-does-it-work-6d16486451ea
97
You might be able to crypto crowdfund on mirror
https://dev.mirror.xyz/llJ_AboiDJwB_ZAFz-CXU7fL2p8v5Wz6MjfluLafewQ
98
For anonymity, I should always upload transactions
Using a new public and private key account held by my master key
99
To expand a solidity tuple into variables but skip one you don't need, type
(uint value1, , uint value2) just add commas but nothing inside
100
CommonJs is a
module system that set conventions for how JS imports files. It uses require("./path.js") and function funcName1() {) function funcName2() {) exports.funcName1 = funcName1 exports.funcName2 = funcName2 or module.exports = { funcName: function() {} }
101
Sequelize sheet
How sequelize works at a high level is You extend their model class with your own class which represents a table and pass in your instance of sequelize on declaration. Then when you call a method on the model and it knows which sequelize object to look for to find the database connection. when you call sequelize.sync() sequelize will check if your sqlite db exists and if not it will create it. To create a new record, type ModelName.create({column: value}).then() To get one record type ModelName.findOne({where: {column: value, column: value}}) You can create a table by Initializing a model const { Model, DataTypes } = require("sequelize"); const sequelize = require("../database.js"); class MyTable extends Model {} MyTable.init({ column: {type: DataTypes.STRING,}, }, { sequelize, modelName: "MyTable", }); module.exports = MyTable; To alter a table, ie drop column/delete table, you must Create and run a migration using their cli A common pattern for updating a record ModelName.findOne({ where: { column: value, column: value} }, }).then(function (obj) { // if it exists, update if (obj) { return obj.update({ column: value }); } // otherwise seralize and save console.log( "There was a transfer on a tokenId: ", data.address, tokenId ); To create a model method type // Class Method ModelName.methodName = function (models) {}; // Instance Method ModelName.prototype.methodName = function () {this.field}; When you change the model definition in the app code and push it to production, there will be a mismatch between the the model representation and the actual database table until you run a migration in production. for django is used to run heroku run db:migrate, which was effectively an ssh and migrate like you would do locally. Then restart would make it work. GPT says that if I want to make db migrations live, adding a column is an exception because you can run the migration and the old app will still work fine. If you altering something the app cares about, then pick a low traffic time, and do both quickly. I wonder if since I cant force users to update mobile apps, i'll need to keep track of versions and always support old versions of the api. You keep multiple versions of the API running concurrently and deprecate the older versions when traffic hit low enough levels. One way of versioning would be to send version info in the HTTP request header, so the URL end point always stays the same. When making changes that break on older clients, update the major version. You can still make changes to the older version but change the minor version number too. You just have to manage this on both the client and server. On the side of managing the code, you could set up models for each version, and use inheritance or delegation for falling back to existing code in older versions because you don't want to keep repeating yourself. When I develop an API endpoint, it has a well-defined and documented set of parameters and response structure. If that contract changes, I make a new version of the endpoint, with a different URL. Newer versions of the client would use the new endpoint, while older versions would still have the old endpoint. Changing the behavior an existing endpoint will likely cause problems for clients "out in the wild" that are currently using it. We went for a simpler approach because we don't want multiple api versions to share the same code, and we want backward compatibility, so we simply place the codes in different directories. E.g. api/v1/xxxx api/v2/xxxx https://www.youtube.com/watch?v=bWFuEVmRgdk
102
Event logs
The problem with listening for events from multiple contracts is you will need to decode the topics yourself. topics[0] is usually a keccak256 hash of the name of the event signature in the following format: "Transfer(address,address,uint256)". No variable names, no spaces, no "event". Note: It includes all parameters, not just indexed parameters (Confirmed in remix) I verified this by running keccak256(abi.encodePacked("Transfer(address,address,uint256)")) and it returned the same value as in my event logs. I can check etherscan to see the format of the events the contracts I need to track have https://etherscan.io/address/0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7#events I confirmed Transfer(address,address,uint256) converts to Loot's topics[0] signature hash by sending it into encodePacked() and keccak() on remix. A hex is basically base16 encoding, although ethereum stores values with left padded zeroes. One hex digit is a nibble, which is half a byte. 64 nibbles = 32 bytes. A 32 bytes hex should have 64 characters. To turn a number into a hex string, you can type let n = 1000 n.toString(16) To turn a hexed number into an integer, type parseInt(Number('0x000000016b9'), 'hex') Note: Javascript uses th 0x at the beginning to represent a hexadecimal string. Note: Ethereum addresses are really just a number converted to a hex string so thats why they are visible with left padding. Solidity stores the hex string versions of the parameter values into topics but also left pads it with 0x000 (lots of zeroes), so you need to use a custom decoder to get the real value in real world applications. For quick checks you can just cut out the 0x000. If one of the topics is a number, it is stored as hex and you can decode it with web3.eth.abi.decodeParameter('uint256', "0x000e52") To decode a hex address from an event topic, type web3.eth.abi.decodeParameter('address', "0x0002b8d5a") The data field stores all event fields that are not indexed in a hex string. Note, all topics and the data field are stored Parameters that are not indexed do not get a topics array item. If the data field is only '0x' it means all the parameters were indexed. This guy implies even non indexed parameters are included in the event signsature hash https://ethereum.stackexchange.com/questions/12950/what-are-solidity-events-and-how-they-are-related-to-topics-and-logs I was getting errors because some contracts do not index the tokenId so I was parsing outside the topics array length of 2 in that case instead of 3 because unindexed events go into the data field.
103
Cryptographic hash function sheet
The main cryptographic hash function in solidity is keccak256 keccak256() takes in an arbitrary size bytes object and returns a bytes32 object which is restricted size. Cryptographic hash functions in general take in an arbitrary size bytes object and return an encoded bytes object of restricted size. The output is deterministic (same input always provide the same output) and you cannot know the input by looking at the output. The input to keccak256() must be of type bytes, so to turn your arbitrary data types into a concatenated bytes object, type abi.encodePacked("string", unint(1), address(efcr4)) To verify you have the correct input for a hash, you need to run the same hash function on the input and see if the outputs are the same https://www.youtube.com/watch?v=rxZR3ITZlzE
104
You only declare the memory location in arguments of function definition if they are of types
string, bytes, array, struct, mapping broadly variable size?
105
You only declare the memory location in arguments of function definition if they are of types
string, array, struct, mapping
106
0x is
a prefix added to numbers to specify they are a hex number aka base 16
107
A serializer is reversible translator, a formatter is not
.
108
Flask sheet
To create the tables defined in SQLAlchecmy, type from main import db db.create_all() into the interpreter To add an object to the database from the interpreter, type db.session.add(obj) db.session.commit() If you add an object to db.session that is not suitable and want to remove all items, type db.session.remove() To get a record, type ModelName.query.filter_by(column_name="value").first() https://flask-sqlalchemy.palletsprojects.com/en/2.x/queries/#querying-records To make a foreign key, type wallet_id = db.Column(db.Integer, db.ForeignKey('wallet.id'), nullable=False) wallet = db.relationship('Wallet', backref=db.backref('nfts', lazy=True)) Gotchas for deploying flask with postgres to heroku: You need pyscopg2 in the requirements, and you need to change heroku's DATABASE_URL to start with postgresql instead of postgres. https://stackoverflow.com/questions/58401435/how-to-use-pip3-install-psycopg2 https://stackoverflow.com/questions/35061914/how-to-change-database-url-for-a-heroku-application After you call db.commit(), your model will have the id property set. Example: db.session.add(user) db.session.commit() print user.id (has id) To make database models in flask, type from flask_sqlalchemy import SQLAlchemy app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///demo.db') db = SQLAlchemy(app) class Wallet(db.Model): id = db.Column(db.Integer, primary_key=True) address = db.Column(db.String(200), unique=True, nullable=False) def __repr__(self): return '' % self.address class Nft(db.Model): id = db.Column(db.Integer, primary_key=True) token_id = db.Column(db.Integer, nullable=False) symbol = db.Column(db.String(200), nullable=False) name = db.Column(db.String(200), nullable=False) description = db.Column(db.Text, nullable=False) image_uri = db.Column(db.String(200), nullable=False) wallet_id = db.Column(db.Integer, db.ForeignKey('wallet.id'), nullable=False) wallet = db.relationship('Wallet', backref=db.backref('nfts', lazy=True)) def __repr__(self): return '' % self.symbol
109
Styling wise, remember to
put all the variable declarations at the top and avoid adding variables you only use once.
110
You cannot count the number of elements inside a
mapping
111
To create a struct and assign values to it, type
struct Person { uint height; // or assign here with = bool alive; address friend; } Person myPerson = Person(10, false, 0xdjer0do3); or struct Drop { uint supply; address[] valuedCollections; string baseUri; address deployer; address minterProxy; mapping (address => uint) usedNfts; } mapping (uint => Drop) drops; Drop storage drop = drops[currentDropId]; Drop storage drop = drops[currentDropId]; drop.supply = supply; drop.valuedCollections = valuedCollections; drop.baseUri = baseUri; drop.deployer = msg.sender; drop.minterProxy = minterProxy;
112
To make a contract pausable, add
bool _paused = false; function _pause() function _unPause() function paused() function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override { super._beforeTokenTransfer(from, to, tokenId); require(!paused(), "ERC721Pausable: token transfer while paused"); }
113
bootstrap
to make a button into a btn-block in bootstrap5 use -div class="d-grid"> -button type="submit" class="btn btn-primary btn-lg">Submit -/div>
114
The smallest subdivision of ether is
wei like a penny
115
web3.py sheet
To call a contract function, type from web3 import Web3 infura_url = "https://mainnet.infura.io/v3/34rf34e" web3 = Web3(Web3.HTTPProvider(infura_url)) abi = json.loads('abi') address = '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07' contract = web3.eth.contract(address=address, abi=abi) totalSupply = contract.functions.totalSupply().call() balance = contract.functions.balanceOf('0xd207').call() To convert Wei to ether, type web3.fromWei(balance, 'ether')) Seems like if I want to use web3.py with metamask, I need to use web3.py to create the transaction, then send that to the client to ask metamask to sign it, and then send the signed version to the server to run the python function.
116
Read only functions do not cost any gas because they
just query your local node, rather than ask the network to change something.
117
In general when you want to use a dictionary with 3 values, use a
struct
118
Dynamic arrays can only use .push() is they are
stored in storage
119
To make a loop, type
Nft[] memory result; for (uint i = 0; i < nfts.length; i++) { if (verifiedNftOwner(nfts[i].contractAddress, msg.sender, nfts[i].tokenId)) { result.push(nfts[i]); } }
120
Develop in remix
test in hardhat
121
If you look up a non existent key in a mapping (string => uint) you will get back If you look up a non existent key in a mapping (string => bool) you will get back
0, false
122
To send money between contracts using interface, type
This is how you handle amount sending between contracts via interface: ContractA.sol: pragma solidity ^0.5.11; contract A { uint256 public lastFundSentToContract = 0; function updateLastFundSentToContract () public payable { lastFundSentToContract = msg.value; } function getContractBalance() public view returns(uint256) { return address(this).balance; } } ContractB.sol: pragma solidity ^0.5.11; contract B { A a_contract_instance; constructor(address _a_contract_address) public { a_contract_instance = A(_a_contract_address); } function callToContractA() public payable { a_contract_instance.updateLastFundSentToContract.value(msg.value)(); } function getContractBalance() public view returns(uint256) { return address(this).balance; } } interface A { function updateLastFundSentToContract () external payable; } But what about arguments? address.function{value:msg.value}(arg1, arg2, arg3) https://ethereum.stackexchange.com/questions/9705/how-can-you-call-a-payable-function-in-another-contract-with-arguments-and-send
123
A nonce is basically a value that makes sure
you dont duplicate a transaction
124
If an error happens in a function you are calling in a remote contract using an interface
the error will cause an error on your function too and propagate back to the user.
125
In metamask, every new account you create gets
a different private key
126
My big mistake when making my ERC20 token was
I didnt use it as an inheritance, I just deployed what they already had without any of my customization.
127
The value of giving names to return values is
The name is a clue on what information should go there. It does not require one to initialize a given variable since it gets initialized automatically with the default/zero value. You don't have to explicitly return it. https://ethereum.stackexchange.com/questions/34046/what-is-the-purpose-of-giving-name-to-return-variables-in-function-declaration
128
Since functions that create transactions take time to verify, they
don't return a value, they return a transaction. You will need to listen to when that transaction is verified and then call a different function to get your value.
129
To create an array that does not require a storage location
it must be fixed length, and you must assign values like below uint[] memory staticArray = new uint[](myArray.length); for (uint i = 0; i < myArray.length; i++) { staticArray[i] = value; } https://www.youtube.com/watch?v=QGjshWJjPPI
130
This guy says you can return a struct from solidity
https://www.youtube.com/watch?v=QGjshWJjPPI
131
To throw an error in solidity, call
revert()
132
a fallback function can be defined
fallback() external { } or function() { }
133
To define a fallback function, type
fallback() external { } The old way is: or function() external { }
134
The only difference between a monetary transaction and a smart contract transaction is
the smart contract transaction will populate the "data:" field with the concatenated function id and parameter values. To get the function id, you keccak256 has the ASCII form of the signature ie. myFunc(type,type) and the only use the first 8 characters in that hash so 0x and then 8 characters. The length of the data parameter with one function argument is always 74 characters (including 0x). Static parameters are encoded in a fairly straightforward manner--they are converted to their hex representation and then concatenated onto the input data hex string. You can encode a parameter using this function https://web3js.readthedocs.io/en/v1.2.0/web3-eth-abi.html#encodeparameter This explains how the dynamic parameters are handled. Essentially the location where it is supposed to be in the sequence is replaced by an index of it's new location, then it gets added to the end of the param array but that value is the character length of the dynamic value, and then the real value comes after that. https://ethereum.stackexchange.com/questions/68558/encoded-input-params
135
To verify code on etherscan using hardhat, type
npx hardhat clean npx hardhat verify --network mainnet deployedAddress "Constructor argument 1" https://hardhat.org/plugins/nomiclabs-hardhat-etherscan.html This can look like it failed in CLI when it actually worked Note: I was failing to verify my file with 2 contracts in it because my interfaces were in between my contracts instead of on top of them (in same file?)
136
To get someone to spend ERC20 tokens to use a smart contract
Make them call approve with your smart contract address so it has an allowance. Then call transferFrom with the address you are trying to take from and the address you are trying to move funds to. Note: The msg.sender must be the account with an allowance from the approve call.
137
To create a contract that creates another contract on a unique address, type
contract A { address owner; string name; string symbol; constructor(address _owner, string memory _name, string memory _symbol) { owner = _owner; name = _name; symbol = _symbol; } function getOwner() public view returns(address) { return owner; } } contract AFactory { mapping (address => address[]) owners; event DeployMinter(address owner, string name, string symbol); function createObject(address owner, string memory name, string memory symbol) public { owners[owner].push(address(new A(owner, name, symbol))); emit DeployMinter(owner, name, symbol); } function getAddresses(address owner) public view returns (address[] memory) { return owners[owner]; } } Note: Since this function creates a transaction, there is no return value returned on etherscan. The only way I know to verify this type of child contract is to run the verify function from hardhat of the same file that creates it. I also failed to verify for a while because I stupidly forgot that I need to pass in the same constructor parameters I used in contract creator function to the verification in order for it to work. Note: If I deploy a contract thats been optimized, it seems the contracts that it deploys will also be optimized.
138
To import a local solidity file, type
import "./MinterFactoryTest.sol";
139
wBTC is
an erc20 token that is holding btc in reserve with 1:1. This requires there being a party storing that btc since the networks cant talk to each other. If someone buys a wBTC it should give them the ability to The wBTC price should be accurate because the market will not want to overpay and will try to underpay.
140
block.timestamp in solidity return
an integer of number of seconds since the “Unix epoch”
141
The default value for an address is a mapping is
address(0) or 0x0000000000000000000000000000000000000000
142
In solidity, as in java, the == operator does not compare the literals of two strings. You should use
the StringUtils contract instead or keccak256(bytes("string")) == keccak256(bytes("signed")).
143
If I have a struct as the value in a mapping, i can rely on it being a defaul value and instantiate it like
Drop storage drop = allDrop[availableDropId];
144
A good explanation of the main encryption schemes
Encoding: Some rules that convert it to a new format Symmetric: One cipher key to encrypt and use same to decrypt Asymmetric: One public key to encrypt, and a different one to decrypt One way hash function: Cannot be decrypted For ethereum : The message is encrypted by the private key and the public key is recovered from the hash by knowing the message contents https://www.youtube.com/watch?v=lnKPoWZnNNM
145
React sheet
Slices basically export your reducer for the rootReducer and your actions. To update the state, the reducers in slices can either modify the state variable without returning anything, or return the full state like the old way, but not both modify and use return. To conditionally render a component, type {true ? : } When you create a slice what you are really doing is creating a reducer you can plug into rootReducer and creating action creators for the synchronous reducers the the reducers field (not the async ones) In slices Async action creators are handled in extraReducers Regular action creators are handled in reducers action creators created by createAsyncThunk automatically get 2 properties, thunkName.pending and thunkName.fulfilled, and these are used as action types so the reducer handles both every function call has to be dispatched. You pass an action creator to a dispatch call. That action creator is either simple or asynchronous. All the action happens in the action creator. To run a function on mount just once type useEffect(() => { }); To create a url with a param, type import { useParams } from 'react-router-dom' function Page() { const { param } = useParams(); -Route path="/drop/:dropUrl" element={} />
146
When setting prices in solidity, no unit after the number is assumed to be
wei assert(1 wei == 1); assert(1 gwei == 1e9); assert(1 ether == 1e18);
147
To multiply two BigNumbers, use
.mul() not *
148
In js, the replacement for a list comprehension is
.filter() which returns true or false to remove items, and .map() which returns a mutated version of each item
149
Metamask lets you request that a user add
a new network, and even switch to that network after they added it.
150
The purpose of -meta name="theme-color" content="#4285f4"> is to
recommend the color of the browser's frame eg: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name/theme-color
151
Having a manifest.json is required by Chrome to show the
Add to Home Screen prompt. It basically gives phones the assets and metadata needed in order to add your app to home screen. https://web.dev/add-manifest/
152
A rollup is basically
a smart contract that holds a merkle root of a large number of transactions that were hashed together off chain. The transaction that updates the merkle root with a new batch takes all the state data as calldata, so the data is saved publicly in the the transaction, but not as variables in the contract. An optimistic rollup allows anyone to update the state but someone else can submit a fraud proof to revert a transaction. 1mb is the limit for calldata, and its 1m characters.
153
If a smart contract does not define a receive function or a payable fallback function, it
cannot receive eth
154
If you send a read transaction and it reverts, you still
pay gas, but left over gas gets refunded
155
The different between revert and require is
revert is better when you need multiple lines of logic before the revert. Require is just one line.
156
To give an element padding using bootstrap, type
p-2
157
To use css modules in react, just
rename the css file to name.module.css In the file import { styles } from './name.module.css' className={styles.class}
158
Sending ether to a smart contract triggers its
fallback function
159
The nonce allows you to be sure that
two transactions from the same address will be mined in the right order
160
To checkout someone else's git branch that only exists in remote, type
git switch branch_name
161
Opensea Sheet
In order for a metadata url to be imported into opensea, it needs to have a url ending in .json
162
It seems you cannot upload private abis to etherscan
on rinkeby, only mainnet
163
Passing a 1 with not unit into ethers as an eth value represents
wei the smallest unit
164
Data
ETL stands for extract, transform, load Basically getting data from multiple places into one place converted into the format you want Spark is used for processing and operating on large data Kafka is a pub/sub messaging system A data pipeline is the tools data travels through to get from one system to another
165
A preflight request tells the browser
which domains are whitelisted on the server, so the browser can enforce preventing the request if its not whitelisted.
166
Zero knowledge proofs
A zk proof allows you to prove that a specific computation ran on values (which can stay private) and yielded a particular return value. A prover is the function that runs your computation and generates a proof that it ran successfully. A verifier is a function that checks if the proof is legit. A witness is a type of proof. An MMO that uses zk proofs https://github.com/darkforest-eth/darkforest-v0.3 A game article https://weijiek.medium.com/how-i-learned-zk-snarks-from-scratch-177a01c5514e A great video using circom https://www.youtube.com/watch?v=Oaub9QwwgCA
167
The way ethereum addresses are generated is
1) Generate a random private key 2) Derive a public key from it using ECDSA 3) Derive an address by keccak hashing that and keeping the last 40 characters https://ethereum.stackexchange.com/questions/3542/how-are-ethereum-addresses-generated