Deploy multiple smart contracts on a single address and interact with them with web3.py

60 views
Skip to first unread message

Yao Marius SODOKIN

unread,
Mar 4, 2024, 5:46:59 PMMar 4
to django...@googlegroups.com
Hello dear all,
I am developing a decentralized application;

It implements smart contracts with solidity. each object represents a smart contract. So I wrote the Transaction, Project, User contracts. I want to deploy these contracts to a single address; and interact with them from my REST API developed in Django Rest Framework, using the web3.py library

The problem I have is:
1-I wrote the code of the three contracts in a single contract, this contract is heavy and cannot be compiled
2- I finally wrote the contracts differently, deployed them to different addresses, and from another contract I want to interact with these contracts. This allows me to interact with a single contract from my API in order to call on others. The size of this contract is also too much and cannot be compiled.
here is the error message:

CompilerError: Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables. When compiling inline assembly: Variable headStart is 1 slot(s) too deep inside the stack. Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables.

How to do ? or what alternative or means used? The objective is to interact with smart contracts deployed from my API in Django Rest Framework

Thanks

kolapo goodness

unread,
Mar 5, 2024, 12:09:09 PMMar 5
to django...@googlegroups.com
evm (ethereum virtual machine) uses the stack data structure and the depth is 1024 so if you get a stack too deep error you should check your solidity code and can also implement some slot packing techniques. the main issue comes from one or more of your functions where you're using a lot of variables if you can reduce it by loading directly from storage instead of local variables that can also solve the problem

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CACiPtiLzQnM9nH%3DiCYaggX4yM9i2kv2-i1dByZGwvDmE1RbkZw%40mail.gmail.com.

Yao Marius SODOKIN

unread,
Mar 5, 2024, 12:22:58 PMMar 5
to django...@googlegroups.com
ok thanks you sir, 
As far as storage variables concerned, I want create many instances of a contrat in my web API, then I use Structs for most of variables, That why I use really locals variables in my functions. if you have resources on it, you recommend to me

Le mar. 5 mars 2024 à 18:08, kolapo goodness <goodnes...@gmail.com> a écrit :
evm (ethereum virtual machine) uses the stack data structure and the depth is 1024 so if you get a stack too deep error you should check your solidity code and can also implement some slot packing techniques. the main issue comes from one or more of your functions where you're using a lot of variables if you can reduce it by loading directly from storage instead of local variables that can also solve the problem

On Mon, Mar 4, 2024 at 11:46 PM Yao Marius SODOKIN <yaomariu...@gmail.com> wrote:
Hello dear all,
I am developing a decentralized application;

It implements smart contracts with solidity. each object represents a smart contract. So I wrote the Transaction, Project, User contracts. I want to deploy these contracts to a single address; and interact with them from my REST API developed in Django Rest Framework, using the web3.py library

The problem I have is:
1-I wrote the code of the three contracts in a single contract, this contract is heavy and cannot be compiled
2- I finally wrote the contracts differently, deployed them to different addresses, and from another contract I want to interact with these contracts. This allows me to interact with a single contract from my API in order to call on others. The size of this contract is also too much and cannot be compiled.
here is the error message:

CompilerError: Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables. When compiling inline assembly: Variable headStart is 1 slot(s) too deep inside the stack. Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables.

How to do ? or what alternative or means used? The objective is to interact with smart contracts deployed from my API in Django Rest Framework

Thanks

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CACiPtiLzQnM9nH%3DiCYaggX4yM9i2kv2-i1dByZGwvDmE1RbkZw%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.

kolapo goodness

unread,
Mar 5, 2024, 1:57:12 PMMar 5
to django...@googlegroups.com
here is an article on managing the *stack too deep* error 
https://soliditydeveloper.com/stacktoodeep

here is also a stackexchange conversation related to it
https://ethereum.stackexchange.com/questions/19587/how-to-fix-stack-too-deep-error

Yao Marius SODOKIN

unread,
Mar 5, 2024, 2:04:39 PMMar 5
to django...@googlegroups.com
OK thanks you. I will check it

Le mar. 5 mars 2024 à 19:57, kolapo goodness <goodnes...@gmail.com> a écrit :
here is an article on managing the *stack too deep* error 
https://soliditydeveloper.com/stacktoodeep

here is also a stackexchange conversation related to it
https://ethereum.stackexchange.com/questions/19587/how-to-fix-stack-too-deep-error

On Tue, Mar 5, 2024 at 6:22 PM Yao Marius SODOKIN <yaomariu...@gmail.com> wrote:
ok thanks you sir, 
As far as storage variables concerned, I want create many instances of a contrat in my web API, then I use Structs for most of variables, That why I use really locals variables in my functions. if you have resources on it, you recommend to me

Yao Marius SODOKIN

unread,
Mar 6, 2024, 5:20:46 PMMar 6
to django...@googlegroups.com
Hello, When I read the sent arritcles on how to fix "stack too deep error", 
it help me solving the problem.

but the problem I have now is that :
Warning: Contract code size is 34894 bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). This contract may not be deployable on Mainnet. Consider enabling the optimizer (with a low "runs" value!), turning off revert strings, or using libraries. --> contracts/funding.sol:7:1: | 7 | contract Funding { | ^ (Relevant source part starts here and spans across multiple lines). I try to compile the contrat with Remix optimizer, but it does not solve the problem. I see this ressource about ; https://forum.openzeppelin.com/t/contract-code-size-exceeds-24576-how-can-i-fix-this-errors/37768/14
after applaying the recomende intructions, it reduce the the size but the error continues. Please help me
This is the contract

// SPDX-License-Identifier: UNLICENSED
//pragma solidity >=0.8.17;
pragma solidity >=0.4.22 <0.9.0;
//pragma experimental ABIEncoderV2;


contract Funding {
//============= ENUMERATIONS =====================
enum TransactionStatus {
INIT,
IN_PROGRESS,
PENDING,
CANCELLED,
COMPLETED
}

enum DocumentStatus {
PENDING,
VALIDATED,
REJECTED
}

enum DocumentType {
CARD_ID,
CIP,
PASSPORT,
PERMIS
}

enum SubscriptionType {
UTILISATEUR,
ENTREPRENEUR,
ASSOCIE,
INVESTISSEUR,
EMPLOYE
}

enum CagnotteStatus {
IN_PROGRESS,
PENDING,
CANCELLED,
COMPLETED
}

enum ProjectStep {
IDEE,
PROTOTYPE,
ENTREPRISE,
ACTION
}

enum ServiceType {
RETRAIT,
RECHARDE,
TRANSFERT,
DEPOT
}


enum EntrepreneurType {
SIMPLE,
ASSOCIE
}

enum EntrepreneurNiveau {
DEBUTANT,
INTERMEDIAIRE,
EXPERIMENTE
}

enum RecetteType {
DEPENSE,
REVENU
}
enum RecetteCategory {
PRODUIT,
SERVICE,
ABONNEMENT
}


enum TypeAdresse {
RESIDENCE,
ORIGINE
}

// =========== Structs ================


struct Transaction {
uint32 sent_amount;
uint32 sent_amount_ussd;

uint32 deducted_amount;
uint32 deducted_amount_ussd;
string slug;
string motif;

string gateway;
uint32 amount_with_fees;
uint32 network_fees_ussd;
uint32 transactions_fees_ussd;

string tx_identifier;
string project_identifier;
address sender;
address receiver;
}


struct Document {
bytes32 unique_hash;
DocumentType doc_type;
string recto_url;
string verso_url;
DocumentStatus status;
uint32 created_timestamp;
}

struct Adress {
string country;
string departement ;
string township ;
string dictrict ;
}


enum AbonnementType { Entrepreneur, Investisseur, Employe, Juriste, Utilisateur }


// event DocumentAdded(bytes32,DocumentType , string);


//event FinancialModalAdded(bytes32,string, string,string,string);


enum ProjectEvolutionStatus {
PENDING,
STARTING,
COMPLETED,
CANCELLED,
FALLEN
}

/* Repetition start*/
struct FinancialModal{
bytes32 unique_hash;
string description;
string[] income_sources;
string rentability_analysis;
string evolutivity_strategy;
string durability_strategy;
string[] partenership ;
string modal_file_url;
uint32 objective_amount;
}

// event ProjectCreated(bytes32,string, string);


struct BusinessPlan{
bytes32 unique_hash;
string[] commercial_objectives;
string marketing_strategy;
uint32 financial_prevision;

string distribution_strategy;
uint32 local_average_price;
string price_fixation_reason;
string[] benefits_means ;

uint32 expected_customer_per_year;
uint32 income_price;
uint32 benefits_marge;
uint32 ussd_average_price;

string business_file_url;
}

struct Charge {
RecetteCategory category;
string libelle ;
string reason;
uint32 amount;
}

struct Contrat {
string type_adhesion;
bytes32 entrepreneur_hash;

bytes32 investor_hash;
string refund_clauses;
uint32 refund_date_delay;
uint32 interest_rate;

string applicable_low;
string investor_rate;
string termination_conditions;
string major_force_clause;

bytes32 competent_juridiction;
string contrat_file;
string contrat_file_url;
bytes32 transaction_hash;
}

struct Project{

string name;
uint32 identifier;
bytes32 unique_hash;
string description;

string problem_to_solve ;
string pertinence;
ProjectStep step;
uint32 production_duration_in_year;

uint32 project_duration_in_year;
string total_amount;
string already_obtained_amount;
FinancialModal financialModal;
BusinessPlan businessPlan;
}


// TODO : Ecrire des fonctions qui les retourne
uint32 internal projet_count = 0;
uint32 internal document_count = 0;
uint32 internal transaction_count = 0;
uint32 internal user_count = 0;


struct UserObject {
string name;
bytes32 hash;
address adress;
string surname;

uint32 bithday;
string email;
string birth_place;
string phone_number;

//string profil_image;
Adress origin_adress;
Adress actual_adress;
AbonnementType abonnement;

uint32[] projectIndexes;
uint32[] documentIndexes;
uint32[] transactionIndexes;
}

//mapping(address => UserObject) internal Users;
mapping(bytes32 => UserObject) private users;

mapping(bytes32 => Project[]) private projects; //projects list
bytes32[] project_hashes ;

mapping(bytes32 => Project[]) private projets;
mapping(bytes32 => Document[]) private documents;
mapping(bytes32 => Adress[]) private addreses;
mapping(bytes32 => Transaction[]) private transactions;
mapping(bytes32 => Contrat) private adhesions;

// function to calculate the financial modal unique hash
function calculate_modal_hash(
bytes32 project_id,
string memory description,
string memory rentability_analysis,
uint32 objective_amount
) internal pure returns(bytes32)
{
return keccak256(abi.encodePacked(project_id, description, rentability_analysis,objective_amount));

}

/*------------ Repetition end ------------*/

// function to calculate the unique hash
function calculate_project_unique_hash(
string memory name,
string memory description,
string memory idea_source
) internal pure returns(bytes32)
{
return keccak256(abi.encodePacked(name, description, idea_source));

}

/**
* function that browse and verify if the project exists
**/
function getOrVerifyProject(bytes32 _address, bytes32 project_hash) internal view returns (bool success, Project memory retrievedProject ) {

(bool succes, ) = getOrVerifyUser(_address); // We verify if the user exists

require(succes, "Not found !");

Project[] memory userProjects = projets[_address];

bool isFound = false;

for (uint32 i = 0; i < userProjects.length; i++) {
if (userProjects[i].unique_hash == project_hash) {
retrievedProject = userProjects[i];
isFound = true;
break;
}
}
success = isFound;

return (success, retrievedProject);
}


function addUser(UserObject memory newUser) public {
bytes32 uniqueHash = keccak256(abi.encodePacked(newUser.hash));

users[uniqueHash] = newUser;
user_count++;
}


function createProject(
bytes32 user_address,
Project memory project
) public {
bytes32 projectHash = calculate_project_unique_hash(project.name, project.description, project.problem_to_solve);

(bool projectExists, ) = getOrVerifyProject(user_address, projectHash);
require(!projectExists, "Already exists !");



FinancialModal memory newModal = FinancialModal({
unique_hash: calculate_modal_hash(projectHash, project.description, "", 0),
description: "",
income_sources: new string[](0),
rentability_analysis: "",
evolutivity_strategy: "",
durability_strategy: "",
partenership: new string[](0),
modal_file_url: "",
objective_amount: 0

});

BusinessPlan memory business_plan = BusinessPlan({
unique_hash :0x0,
commercial_objectives : new string[](0),
marketing_strategy : "",
financial_prevision :0,
distribution_strategy:"",
local_average_price: 0,
price_fixation_reason :"",
benefits_means : new string[](0),
expected_customer_per_year:0,
income_price :0,
benefits_marge:0,
ussd_average_price:0,
business_file_url : ""
});

projects[user_address].push(Project({
name: project.name,
unique_hash: projectHash,
identifier : project.identifier,
description: project.description,
problem_to_solve: project.problem_to_solve,
pertinence: project.pertinence,
step: project.step,
production_duration_in_year : project.production_duration_in_year,
project_duration_in_year : project.project_duration_in_year,
total_amount: project.total_amount,
already_obtained_amount: project.already_obtained_amount,
financialModal: newModal,
businessPlan : business_plan
}));

(bool success, ) = getOrVerifyUser(user_address);
require(success, "Not found!");

UserObject storage userStorage = users[user_address];
projects[user_address] = projects[user_address];

projet_count++;
userStorage.projectIndexes.push(projet_count);
project_hashes.push(projectHash);

//emit ProjectCreated(projectHash, project.name, "Created successfully!!");
}


/**
* function that browse and verify if the user exists
* it return a tuple that contains a boolean indicatinf the existence et the Userobject if true
**/
function getOrVerifyUser(bytes32 _hash) public view returns (bool success, UserObject memory verifiedUser ) {

bool isFound = bytes(users[_hash].name).length > 0;

if(isFound)
{
verifiedUser = users[_hash];
success = isFound;

}
return (success, verifiedUser);
}


//===========================================
// Add the User Documents
function AddDocumentToUser(
bytes32 user_hash,
Document memory document
) public {
bytes32 doc_unique_hash = keccak256(abi.encodePacked(document.doc_type, document.recto_url,document.verso_url ));

(bool success, ) = getOrVerifyUser(user_hash);
require(success, "Not found !");

UserObject storage userStorage = users[user_hash];
documents[user_hash].push(Document({
unique_hash: doc_unique_hash,
doc_type : document.doc_type,
recto_url :document.recto_url,
verso_url : document.verso_url,
status : DocumentStatus.VALIDATED,
created_timestamp : 0
}));

document_count++;

userStorage.documentIndexes.push(document_count); // Add doc to user doc

}


function addAdhesion(
Contrat memory adhesion
) public {
bytes32 uniqueHash = keccak256(abi.encodePacked(adhesion.entrepreneur_hash, adhesion.investor_hash, adhesion.transaction_hash));

// Ajouter l'adhésion au mapping des adhésions
adhesions[uniqueHash] = Contrat({
type_adhesion: adhesion.type_adhesion,
entrepreneur_hash: adhesion.entrepreneur_hash,
investor_hash: adhesion.investor_hash,
refund_clauses: adhesion.refund_clauses,
refund_date_delay: adhesion.refund_date_delay,
interest_rate: adhesion.interest_rate,
applicable_low: adhesion.applicable_low,
investor_rate: adhesion.investor_rate,
termination_conditions: adhesion.termination_conditions,
major_force_clause: adhesion.major_force_clause,
competent_juridiction: adhesion.competent_juridiction,
contrat_file: adhesion.contrat_file,
contrat_file_url: adhesion.contrat_file_url,
transaction_hash: adhesion.transaction_hash
});

}


function getAdhesion(bytes32 contrat_hash) public view returns (Contrat memory) {
return adhesions[contrat_hash];
}

// Add the User Adresse
function AddAdressToUser(
bytes32 user_hash,
Adress memory adress,
uint _type
) public {

require(_type==0 || _type==1, "Not valid!");

(bool success, ) = getOrVerifyUser(user_hash);
require(success, "Not found!");

UserObject storage userStorage = users[user_hash];

if (_type==0)
{
userStorage.actual_adress = Adress({
country: adress.country,
departement :adress.departement,
township :adress.township,
dictrict : adress.dictrict
});
}
else {
userStorage.origin_adress = Adress({
country: adress.country,
departement :adress.departement,
township :adress.township,
dictrict : adress.dictrict
});
}
}

function setUserAbonnementType(bytes32 hash, AbonnementType _abonnement) public {
(bool success, ) = getOrVerifyUser(hash);
require(success, "Not found!");
UserObject storage userStorage = users[hash];
userStorage.abonnement = _abonnement;
}

// Add the Transaction Documents
function CreateUserTransaction(
bytes32 user_hash,
Transaction memory transaction
) public {
(bool success,) = getOrVerifyUser(user_hash);
require(success, "Not found!");

transactions[user_hash].push(Transaction({
sent_amount: transaction.sent_amount,
sent_amount_ussd: transaction.sent_amount_ussd,
deducted_amount: transaction.deducted_amount,
deducted_amount_ussd: transaction.deducted_amount_ussd,
slug: transaction.slug,
motif: transaction.motif,
gateway: transaction.gateway,
amount_with_fees: transaction.amount_with_fees,
network_fees_ussd: transaction.network_fees_ussd,
transactions_fees_ussd: transaction.transactions_fees_ussd,
tx_identifier: transaction.tx_identifier,
project_identifier: transaction.project_identifier,

sender: transaction.sender,

receiver: transaction.receiver

}));


}

function getUserDocuments(bytes32 userHash) public view returns (Document[] memory) {
(bool success,) = getOrVerifyUser(userHash);
require(success, "Not found !");
Document[] memory userDocuments = documents[userHash];
return userDocuments;
}

function getUserTransactions(bytes32 userHash) public view returns (Transaction[] memory) {
(bool success,) = getOrVerifyUser(userHash);
require(success, "Not found!");
Transaction[] memory userTransactions = transactions[userHash];
return userTransactions;
}
function getUserProjects(bytes32 userHash) public view returns (Project[] memory) {
(bool success,) = getOrVerifyUser(userHash);
require(success, "Not found!");
Project[] memory userProjects = projects[userHash];
return userProjects;
}

function getAllUsers(bytes32 user_hash) public view returns (UserObject memory) {
(bool success,) = getOrVerifyUser(user_hash);
require(success, "Not found !");
return users[user_hash];
}

function getUserSpecificProject(bytes32 userHash, uint32 projectId) public view returns (Project memory) {
(bool success,) = getOrVerifyUser(userHash);
require(success, "Not found !");
return projects[userHash][projectId];
}

function setProductionDuration(bytes32 userHash, uint32 projectId, uint32 _duration) public {
projects[userHash][projectId].production_duration_in_year = _duration;
}

function setProjectDuration(bytes32 userHash, uint32 projectId, uint32 _duration) public {
projects[userHash][projectId].project_duration_in_year = _duration;
}

function setProjectStep(bytes32 userHash, uint32 projectId, ProjectStep _step) public {
projects[userHash][projectId].step = _step;
}


function addIncomeSourceToModel(bytes32 userHash, uint32 projectId, string memory _source) public {
projects[userHash][projectId].financialModal.income_sources.push(_source);
}

function addIncomePartnerShipToMOdal(bytes32 userHash, uint32 projectId, string memory _partner) public {
projects[userHash][projectId].financialModal.partenership.push(_partner);
}

function AddFinancialModal(
bytes32 userHash,
uint32 projectId,
FinancialModal memory fiancial_model
) public {
// bytes32 uniqueHash = keccak256(abi.encodePacked(userHash, projectId, fiancial_model.objective_amount));

projects[userHash][projectId].financialModal = FinancialModal({
unique_hash: fiancial_model.unique_hash,
description: fiancial_model.description,
income_sources: fiancial_model.income_sources,
rentability_analysis: fiancial_model.rentability_analysis,
evolutivity_strategy: fiancial_model.evolutivity_strategy,
durability_strategy:fiancial_model.durability_strategy,
partenership: fiancial_model.partenership,
modal_file_url: fiancial_model.modal_file_url,
objective_amount: fiancial_model.objective_amount
});

}


}




Le mar. 5 mars 2024 à 20:03, Yao Marius SODOKIN <yaomariu...@gmail.com> a écrit :
OK thanks you. I will check it

Reply all
Reply to author
Forward
0 new messages