Libraries on Ethereum

First off, there’s 3 ways to call a function on a contract. CALL, CALLCODE, and DELEGATECALL.

Libraries on Ethereum are largely implemented with DELEGATECALL. Meaning, you deploy a contract that serves as a library — it’s got some functions that anyone can call, and can even change the storage of the calling contract.

Solidity has some syntactic sugar that lets you declare a library, which does all the DELEGATECALLs for you if you use the library in your contract. But on the EVM level it is the same as deploying them as contracts.

Parity’s library contract

Parity initially deployed a mutisig contract as their library. The library itself is a very much working multisig wallet. On a hindsight it probably shouldn’t be.

Then all the other multisig wallets have this in their code:

address constant _walletLibrary = 0x863df6bfa4469f3ead0be8f9f2aae51c91a907b4

Since it’s a constant, it’s populated at compile time, meaning it’s permanently stored in “code”, not “storage”. The value would be the address of the library to DELEGATECALL on. If you run eth.getCode(walletAddress) on one of the affected wallets, you should see the address of the now-dead library at index 422.

On another hindsight, it should probably allow users to change the linked library address, instead of coding it in the bytecode.

Killing the library contract

Since the library itself is a working wallet, and it was left uninitialized, anyone would be able to call initWallet on the library contract. The “hacker” did it in this transaction. The call is perfectly legal, zero tricks involved, since he’s just initializing a wallet that’s not been initialized.

Now that he is the owner of the library contract, he can call any privileged function he wants. So he called kill in this transaction. The kill function basically calls suicide (which is now being replaced by selfdestruct, they do the same thing). suicide destroys the contract, clears its storage and code, sending remaining funds to the owner. (which is zero, the library itself holds no funds)

Code becomes zero

Now every function call to the now-dead library will simply return false, or 0.

All the multisig wallet contracts that rely on the library contract code would now get zero when they DELEGATECALL. The multisig wallet contracts still hold funds, they have not been hacked, but all the library code is zeroed out.

The multisig wallets are essentially locked. Most of the functionalities (including the kill-switch function) rely on the library which is now returning zero for every function call.

The only way to resume their functionalities would be a hard fork to add the library code back.


Can you statically link the libraries?

It is very possible to contain all the library code in the multisig wallet contract itself, instead of doing DELEGATECALLs to an external contract. This is similar to static linking in a sense. It will increase the gas cost of contract deployment though.