ape icon indicating copy to clipboard operation
ape copied to clipboard

Export Solidity functions as Python functions

Open gabrielfior opened this issue 1 year ago • 5 comments

Overview

I want to generate Python functions from a smart contract's ABI definitions.

Specification

I would expect this to be part of the ape.contracts package.

Dependencies

For reference, I found some (old) implementations that don't actually do what I'm thinking. https://github.com/Consensys/python-solidity-parser/tree/master (last commit 3 years ago)

This also goes in the right direction -> https://github.com/ethereum/web3.py/issues/3016

gabrielfior avatar Jul 19 '24 14:07 gabrielfior

This would take a larger refactor to move to a more functional, metaclass-style method for generating ContractContainer singleton classes from ethpm_types.ContractType models which can be instantiated (and enhanced with other information from ContractType such as NatSpec docs, etc.)

@BobTheBuidler might find this idea interesting, he was looking for a way to avoid having multiple instances of ContractType models to reduce the memory usage of Ape with large amounts of instances with the same contract type

cc @antazoey @bitwise-constructs who are thinking about overall improvements to contract ergonomics

fubuloubu avatar Jul 19 '24 20:07 fubuloubu

I just want to have some things to visualize for us to discuss, as this might be something we want to consider for 0.9.

Currently:

>>> from ape import project
>>> project.MyContract

Note: currently, all contract-types are the same class and not individual classes (not generated at runtime via ABI)

Proposition:

>>> from ape.contracts import MyContract

The new MyContract is something generated at runtime via the ABI. All methods are readidly available. Structs are the same, we already use meta-classes for those, same with errors.

^ That last sentence is a good point: we are already using metaclass / runtime type generation for errors and structs, so one more step to ContractType feels right.

Anyway, the downside is the metaclass are weird, but I think one can just expect that... like you can't use issubclass and some other stuff like that.

antazoey avatar Jul 24 '24 18:07 antazoey

Proposition:

>>> from ape.contracts import MyContract

As an overall note, this level of change (migrating from using ape.project.MyContract to ape.contracts.MyContract) would be a v1.0 type of breaking change


Further, I don't think I like automatically generating imports. That's what Brownie used to do, and it's very difficult because you pollute the namespace of the module. It can be much more simple that project.__getattr__ uses keys from the current project's known contract types and generates custom classes using ContractContainer more as a metaclass (or we can get rid of ContractContainer entirely). Still, like you said it would be a breaking change to remove ContractContainer from the class heirarchy (and ContractInstance, which subclasses ape.api.address.BaseAddress) but there are ways of just applying a common parent class when forming the metaclass to maintain that heirarchy for all the generated subclasses.

In a similar vein, we can probably do the same with MethodABI objects to generate custom method handlers as metaclasses and insert them into the ContractInstance objects (closer to what this issue's OP is talking about) This might also be a breaking v1.0 level change due to the change of metaclasses, type annotation support, etc. (I think I am using ContractMethodHandler inside of ape-safe and the multicall module)

fubuloubu avatar Jul 24 '24 22:07 fubuloubu