These are some of the most popular questions out there, along with my personal choices. You can easily find good answers for them online, but I’ll chime in and save you some time. Hopefully, with a much less boring formality typical of, well, StackOverflow.


SOLIDITY Q&A


Purpose of ‘memory’ keyword

The compiler will automatically choose to store values either in memory (temporary, cheaper) or storage (permanent, expensive) depending on the type and scope of the variable.

But ‘automatic’ choices made on your behalf don’t sound ideal, maybe even dangerous. So you should be explicit. All day, every day.


SPDX license identifier

Long story short, solidity source code is often published to establish trust. And published source code always touches on liability and copyright.

The compiler will complain if you don’t specify the license for your source-code. It requires a machine-readable declaration, using this format:

// SPDX-License-Identifier: MIT

You can also choose:

// SPDX-License-Identifier: UNLICENSED

All available identifiers are here.


Strings: concatenation, conversion, comparison, dynamic arrays

This is Solidity, not JavaScript. Run away from strings! This is more important than any technical explanation. Your code is meant to be short, efficient, and use as little storage as possible. In many cases, you can replace strings with enums, constants… be creative. Your code is not meant to be readable by a CS student, although you can (and should) always write clear comments.

If you still need to mess with them, strings are dynamically-sized UTF-8-encoded arrays. Pretty much a bytes type.

function StringMethods() public pure returns (string memory, uint) {
    string memory name = "Zasnicoff";
    uint len = bytes(name).length; // to get size in bytes
    bytes(name)[0] = "z"; // to access index
    return (name, len); // returns ("zasnicoff", 9)
}

There’s no straight way to compare strings, because their sizes are unknown at compile time. You can compare hashes of the encoded strings:

keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))

To concatenate:

function Concatenate() public pure returns (string memory) {
    string memory name = "Zasnicoff";
    string memory site = string.concat(name, ".com");
    return site; // returns "Zasnicoff.com"
}

Payable address

At some point along the upgrades (^0.8.0 ?), the compiler started to require an explicit declaration for addresses that can receive ETH. This is to avoid mistakes, you know, force you to behave.

// EOA or contract
address payable receiver = payable(0xC92d...);
receiver.transfer(1);

// EOA or contract
address receiver2 = 0x0019...;
payable(receiver2).transfer(2);

Is this address a contract?

If the address already exists, you can either visit Etherscan, query low-level data from the blockchain, or programmatically check the account’s code size (contracts will have a run-time code (virtual ROM):

require(account.code.length > 0, "not a contract, or is it?");

But… If your contract is checking the code size of another contract being deployed at the same time (same block), code.length will return 0. This new contract will have a runtime code only after the block is mined. So the newborn contract can trick you during deployment, using its constructor to interact with your contract. This opens an attack vector for malicious contracts to receive ETH, and, you know… flash loan attacks, reentrancy. And that was probably the whole point of checking to begin with. Don’t rely on this code to make your assertion. If you find a safe way to check, well, you’ll be king!


JAVASCRIPT (ethers.js) Q&A

to be continued…


THE GRAPH / SUBGRAPHS Q&A

to be continued…