nft-generator-py

nft-generator-py is a python based NFT generator which programatically generates unique images using weighted layer files. The program is simple to use, and new layers can be added by adding a new layer object and adding names, weights, and image files to the object.
You can View The Demo here.
Usage
As of v2.0.0, nft-generator-py will use the argparse library in order to support external configuration files and won't require users to interact with the python files themselves.
-
Install requirements: python3 -m pip install -r requirements.txt
-
Make a configuration JSON file. See the configuration section below for specifications.
-
Add layer files into the /images
folder.
-
Run the command python3 generate.py --amount AMOUNT --config CONFIG
where:
AMOUNT
is the amount of images to generate
CONFIG
is the path pointing to a .json
file containing valid program configuration.
How it works
- A call to
generate_unique_images(amount, config)
is made, which is the meat of the application where all the processing happens.
- The
config
object is read and for each object in the layers
list, random values are selected and checked for uniqueness against all previously generated metadata files.
- Once we have
amount
unique tokens created, we layer them against eachother and output them and their metadata to their respective folders, ./metadata
and ./images
.
Configuration
{
"layers": [
{
"name": "Background",
"values": ["Blue", "Orange", "Purple", "Red", "Yellow"],
"trait_path": "./trait-layers/backgrounds",
"filename": ["blue", "orange", "purple", "red", "yellow"],
"weights": [30, 45, 15, 5, 10]
},
...
],
"incompatibilities": [
{
"layer": "Background",
"value": "Blue",
"incompatible_with": ["Python Logo 2"]
},
],
"baseURI": ".",
"name": "NFT #",
"description": "This is a description for this NFT series."
}
The config
object is a dict that contains configuration instructions that can be changed to produce different outputs when running the program. Within metadata files, tokens are named using the configuration's name
parameter, and described using the description
parameter.
- In ascending order, tokenIds are appended to the
name
resulting in NFT metadata names such as NFT #0001.
- tokenIds are padded to the largest amount generated. IE, generating 999 objects will result in names NFT #001, using the above configuration, and generating 1000 objects will result in NFT #0001.
- As of
v1.0.2
, padding filenames has been removed.
The layers
list contains layer
objects that define the layers for the program to use when generating unique tokens. Each layer
has a name, which will be displayed as an attribute, values, trait_path, filename, and weights.
trait_path
refers to the path where the image files in filename
can be found. Please note that filenames omit .png, and it will automatically be prepended.
weight
corresponds with the percent chance that the specific value that weight corresponds to will be selected when the program is run. The weights must add up to 100, or the program will fail.
The incompatibilities
list contains an object that tells the program what layers are incompatible with what. In the above configuration, A Blue Background layer
will never be generated with Python Logo 2.
layer
refers to the targeted layer.
value
is the value of the layer that is incompatible with attributes within the incompatible_with
list.
incompatible_with
is the list of incompatible layers that will never be selected when layer
has attribute value
.
As of v1.0.2
, the IPFS CID may be updated programatically after generating NFTs and uploading /images
to IPFS. This will update all metadata files to correctly point "image"
to the IPFS CID.
- This is an optional step, and can be exited safely using
enter
or control + c
.
Troubleshooting
- All images should be in .png format.
- All images should be the same size in pixels, IE: 1000x1000.
- The weight values for each attribute should add up to equal 100.
Credits
This project is completely coded by Jonathan Becker, using no external libraries.
Unique image & metadata generation using weighted layer collections.
Heimdall

Heimdall is an advanced and modular smart-contract toolkit which aims to make dealing with smart contracts on EVM based chains easier.
Installation & Usage

pip install eth-heimdall
Heimdall operates off the argparse
library, with modules specifying which operation you with to perform.
heimdall [-m/--module] MODULE [-v] [--default] [-arguments]
Modules & Help
You may find the various modules supported by Heimdall by using the -h option, which opens the help menu by default.
Options:
-h, --help Show the help message and exit
-hh Show advanced help message and exit
--version Display version information and exit
--update Updates heimdall to the latest release
-v, --verbose Toggle verbose output
Modules:
Below is a list of modules currently supported on Heimdall
# | Name | Description
| |
0 | Config | Easily modify the configuration on Heimdall
1 | Debug | Easily access Heimdall debug information
2 | Decompile | Decompile and download the target smart contract
Parameters:
-m MODULE, --module MODULE Operation module, either name or number from list
-t TARGET, --target TARGET Target of operation (file, transaction id,
or address)
-o PATH, --output PATH Path to write output to
-c ID, --chain ID Chain ID of target
-p URL, --provider URL URL of custom Ethereum provider
Additional:
--open, --edit Attempts to open nano / edit on the operation
--redeploy ID Redeploys the contract from -n onto ID
--beautify Attempts to beautify the downloaded contract using
statistical renaming and spacing
--default Always use defaults when prompted for input
--flush, --ignore-cache Flushes the cache and rewrites it
Please keep in mind as more modules are released, module numbers may change. It's recommended to use the module name instead.
Module Documentation
Specific module documentation can be found in the /docs
folder, or quickly navigate using the links beow.
Configuration
You may save environment information, such as remote and local providers, to the configuration folder in env/conf.json
.
Contributing
If you'd like to contribute to Heimdall or add a module, please open a pull-request with your changes, as well as detailed information on what is changed, added, or improved.
Modules
To add a module, you must add a .py
file within the /lib/modules
folder. In order for your pull-request to be accepted, your module must begin with a meta
object, which is used when displaying what it does to end-users.
Example meta object:
meta = {
"title": "Decompile",
"description": "Decompile and download the target smart contract",
"author": "Jonathan Becker <jonathan@jbecker.dev>",
"version": "v1.0.0",
}
You will also need to add detailed documentation to this readme file in the Module Documentation
section.
Troubleshooting
If you encounter an issue, please create one using the link below. You MUST follow the issue format, or it will be marked as invalid.
Issues that remain inactive for 72 hours will be marked inactive and closed. If your issue is accepted by a contributor, they will assign themselves to it and add corresponding tags.
Credits
This project is coded in its entirety by Jonathan Becker. Various contributors can be found in the sidebar.
Powerful Ethereum Smart-Contract Toolkit
Recurring Payments on Ethereum

Recurring payments on the blockchain have been a topic of discussion for some time. First introduced in EIP-1337 in 2018, the proposal never really caught on. My approach to recurring payments on Ethereum takes a simpler approach than EIP-1337 did, which may help it have a larger impact on the community.
You can find this PoC write-up on my research page.
Live demo's of the contract can be found on the Ropsten network at the following links:
RecurringPayments: https://ropsten.etherscan.io/address/0xF4EfF5176bA24156d483Fddf89A09aAA12e67bAB
ERC-20: https://ropsten.etherscan.io/token/0x119b1b4697d31589fa209ba627355BfB20bebDA6
0x01. Abstract
The recurring payment implementation I will explore throughout this paper is an application of the ERC-20 Token Standard's approve(...)
function. An unlimited allowance (2^256-1
) is approved to the subscription contract address, which periodically allows the _payee
to call a timelocked proxy of ERC-20's transferFrom(...)
method.
0x02. Detailed Analysis
Consequences
Pros:
_spender
must only call 2 transactions to create a subscription; approve(...)
and createSubscription(...)
.The burden is on the payee to call the transferFrom(...)
proxy, meaning they must pay the gas fees to process future payments.
- Subscriptions can be cancelled at any time, by either the
_spender
or the _payee
.
Cons:
- This approach requires an unlimited* approval to the smart contract handling the recurring payments.
- * Technically, this approval can be any amount as long as the
_spender
approves at least enough to pay for a minimum of 2 transactions. Although unlimited approvals of ERC-20 tokens are against Solidity best practice, this PoC allows for recurring payments on Ethereum in a generally secure manner, where the only potential losses lie in the smart contract's integrity.
- We rely on
block.timestamp
for the timelock. This is generally not an issue, but should be noted.
Specification
Methods
-
getSubscription
Returns the Subscription of _customer
to _payee
.
function getSubscription(address _customer, address _payee) public view returns(Subscription memory)
-
subscriptionTimeRemaining
Returns the time in seconds remaining until the subscription payment may be charged again.
function subscriptionTimeRemaining(address _customer, address _payee) public view returns(uint256)
-
createSubscription
Creates a Subscription which allows _payee
to charge the caller _subscriptionCost
every _subscriptionPeriod
, until the Subscription is cancelled.
This may only be called by the customer, and will automatically charge them for the first billing period. Requires an approval to the subscription contract address of _subscriptionCost * 2
.
Emits a Transfer
, NewSubscription
, and SubscriptionPaid
event.
function createSubscription(address _payee, uint256 _subscriptionCost, address _token, string memory _name, string memory _description, uint256 _subscriptionPeriod ) public virtual
-
cancelSubscription
Cancels a subscription between _customer
and _payee
and disallows further executePayment(...)
calls.
This can be called by either party.
function cancelSubscription(address _customer, address _payee ) public virtual
-
executePayment
Charges _customer
for the subscription between _customer
and the payee a total of _subscriptionCost
, given that they have enough token balance and _subscriptionPaid
is false
.
This must be called by the payee.
function executePayment(address _customer) public virtual
-
_subscriptionPaid
An internal function that returns true
if the subscription between _customer
and _payee
has been paid for the current period, or false
if otherwise.
function _subscriptionPaid(address _customer, address _payee) internal view returns(bool)
Events
-
NewSubscription
MUST be called whenever a new subscription is created.
event NewSubscription(Customer, Payee, Allowance, TokenAddress, Name, Description, LastExecutionDate, SubscriptionPeriod);
-
SubscriptionCancelled
MUST be called whenever a new subscription is cancelled.
event SubscriptionCancelled(Customer, Payee);
-
SubscriptionPaid
MUST be called whenever a new subscription is paid.
event SubscriptionPaid(Customer, Payee, PaymentDate, PaymentAmount, NextPaymentDate);
0x04. Conclusion
This method of allowing smart-contracts to recursively call transferFrom(...)
based on an timelocked proxy function enables subscriptions on the blockchain, one of the most important aspects when it comes to running a service or business. The approach this PoC takes is also trustless, and can be revoked any time by the owner, allowing for a truly decentralized form of recurring payments & subscriptions on Ethereum.
0x05. Resources & Citations
- Fabian Vogelsteller, Vitalik Buterin, "EIP-20: Token Standard," Ethereum Improvement Proposals, no. 20, November 2015. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-20.
- Kevin Owocki, Andrew Redden, Scott Burke, Kevin Seagraves, Luka Kacil, Štefan Šimec, Piotr Kosiński, ankit raj, John Griffin, Nathan Creswell, "EIP-1337: Subscriptions on the blockchain," Ethereum Improvement Proposals, no. 1337, August 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1337.
Ethereum-Recurring-Payments
A PoC for recurring payments on Ethereum using the ERC20 standard and a timelocked proxy of transferFrom().
Revoke.Finance

Revoke.finance is a simple DApp which allows users to see all open token approvals on their Ethereum account and manage them in an elegant React UI. I made this project after witnessing the DDoSing of revoke.cash as well as etherscan.io during the February 19 OpenSea phishing attack.
This project will be deployed to IPFS and will be DDoS proof as long as one node is hosting the file. All valid IPFS CIDs can be found on Revoke.finance, which will be updated as the project recieves further updates.
URL: https://revoke.finance/
IPFS Mirror: ipfs://bafybeifvkg4o5b7vxitg46xevmgmza7rkjjhc6fd2dx6spl5rnrkfxgiru
0x01. Features
ERC20 Approval List
The main feature of this project is the approval list, which will show all active approvals from supported ERC-20 tokens. This allows users to view the Token
, Contract Address
, Spender Address
, and Allowance Amount
for each approval, and give them the option to edit or revoke this approval.
Incident Feed
Another valuable feature of this DApp is the incident feed, which will allow users to see in real-time incidents that are ongoing within the cryptospace. This includes hacks, exploits, or bugs, and will allow users on the application to see which approvals may be risked due to an ongoing incident.
Open Source
This entire project is open-source and crowdsourced. If you have an ERC-20 token you want supported, or want to report an incident, all you have to do is open a pull-request and it will be added to the DApp. For more information on contributing, see the next section.
0x02. Contributing
Adding support for a token
If you want to add support for a token or change token information, follow these steps:
-
- Fork this repository
-
- Add or edit the token within public/assets/json/erc20.json.
- In order to be accepted, follow the JSON format below:
{
chainId: number, // Chain ID
address: string, // Contract address
name: string, // Name of token, 40 chars max
symbol: string, // Symbol of token, 20 chars max
decimals: number, // Number of decimals token uses
logoURI: string | null, // URI / URL for token logo
extensions: {
link: string | null, // URL of token's website
description: string | null, // Short description of token (1000 chars max)
ogImage: string | null // URL of Open Graph image of token website
}
}
- Fields that do not exist should be marked
null
.
-
- Open a pull request to the main branch.
- If you are updating a token, explain why within your PR.
Reporting an Incident
If you are reporting an incident that is ongoing or has happened in the past, follow these steps:
-
- Fork this repository
-
- Add or edit the incident within public/assets/json/incidents.json.
- In order to be accepted, follow the JSON format below:
{
severity: string , // high, medium, or low
platform: {
name: string, // Name of platform
address: string | null, // Contract address of platform
logoURI: string | null, // Link to platform Logo
},
description: string, // Detailed description of incident (50 char min, 1000 max)
source: string | null, // Valid source regarding incident
date: string, // Date of incident, YYYY-MM-DD HH24:MM:SS (2022-03-05 23:59:59)
}
- Fields that do not exist should be marked
null
.
-
- Open a pull request to the main branch.
- If you are updating an incident, explain why within your PR.
0x03 Resources & Citations
A simple DApp which allows users to see all open token approvals on their Ethereum account and manage them in an elegant React UI.
sudoku-solver-py
soduku-solver-py is a simple program I challenged myself to create in 6 hours in python. Python is a language I need the most practice with, so I felt like this would be a good project to challenge that. This was a timed challenge, so there are most likely bugs, and it is not efficient at all.
How it works
You can View The Demo here, but basically heres the meat of the application.
- An object
Board
is generated which contains self.board
and self.backup
, with various helper classes such as Board.restoreBackup()
and Board.canPlaceNumber
.
- The
self.board
object is an array of 9 1 x 9 arrays, for example: [[2,8,0,0,0,0,0,0,1],
[0,0,0,8,0,1,0,0,4],
[0,0,4,0,7,0,3,0,0],
[0,2,0,0,5,0,0,6,0],
[0,0,3,1,0,9,7,0,0],
[0,1,0,0,8,0,0,5,0],
[0,0,1,0,6,0,8,0,0],
[5,0,0,2,0,3,0,0,0],
[9,0,0,0,0,0,0,1,6]]
- The program then generates an array
potentialBoardValues
, and assigns each blank space an array with all numbers that could be possible numbers for that space.
- We loop through
potentialBoardValues
and find where only 1 value can be placed there. This action is repeated until there are no more guaranteed values.
- We now recursively loop through
potentialBoardValues
, assigning numbers and searching for singular possibilities, reverting to a backup board when an invalid board is encountered.
- At some point the board will be solved, which can take anywhere from 1 second to 1 minute, since its not very efficient at all.
Todo
If I ever do revisit this project, I need to revamp the correction system so it goes back to the furthest correct point. Right now, we backup to the beginning when encountering an invalid board, which exponentially increases solve times.
Credits
This project is completely coded by Jonathan Becker, using no external libraries.
A simple project that I wrote that solves sodukos.
node-temp-mail
Node wrapper for creating and fetching temporary, disposable emails, as well as their new messages.
Installation
npm install node-temp-mail
Usage
var TempMail = require('node-temp-mail');
// Let's create an address object so it can be accessed by the module.
var address = new TempMail("testAddress");
// We already have the address object, so now let's access it and get a list of the emails in a nice & neat json object.
address.fetchEmails(function(err,body){
console.log(body);
});
// If for any reason you need to see the full temporary email address, you can use the following function.
address.getAddress()
Node wrapper for creating and fetching temporary, disposable emails, as well as their new messages.