Skip to content

Commit

Permalink
ERC2981 (Royalty Info) for Cairo (#413)
Browse files Browse the repository at this point in the history
  • Loading branch information
immrsd authored Dec 2, 2024
1 parent a079802 commit 2bf262c
Show file tree
Hide file tree
Showing 29 changed files with 1,536 additions and 78 deletions.
4 changes: 4 additions & 0 deletions packages/core-cairo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.19.0 (2024-11-27)

- Add ERC2981 (RoyaltyInfo) for ERC721 and ERC1155 ([#413](https://github.com/OpenZeppelin/contracts-wizard/pull/413))

## 0.18.0 (2024-11-15)

- **Breaking changes**:
Expand Down
2 changes: 1 addition & 1 deletion packages/core-cairo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openzeppelin/wizard-cairo",
"version": "0.18.0",
"version": "0.19.0",
"description": "A boilerplate generator to get started with OpenZeppelin Contracts for Cairo",
"license": "MIT",
"repository": "github:OpenZeppelin/contracts-wizard",
Expand Down
25 changes: 24 additions & 1 deletion packages/core-cairo/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface Contract {
superVariables: Variable[];
}

export type Value = string | number | { lit: string } | { note: string, value: Value };
export type Value = string | number | bigint | { lit: string } | { note: string, value: Value };

export interface Component {
name: string;
Expand Down Expand Up @@ -57,6 +57,7 @@ export interface BaseImplementedTrait {
}

export interface ImplementedTrait extends BaseImplementedTrait {
superVariables: Variable[];
functions: ContractFunction[];
}

Expand Down Expand Up @@ -172,6 +173,7 @@ export class ContractBuilder implements Contract {
name: baseTrait.name,
of: baseTrait.of,
tags: [ ...baseTrait.tags ],
superVariables: [],
functions: [],
priority: baseTrait.priority,
};
Expand All @@ -180,6 +182,27 @@ export class ContractBuilder implements Contract {
}
}

addSuperVariableToTrait(baseTrait: BaseImplementedTrait, newVar: Variable): boolean {
const trait = this.addImplementedTrait(baseTrait);
for (const existingVar of trait.superVariables) {
if (existingVar.name === newVar.name) {
if (existingVar.type !== newVar.type) {
throw new Error(
`Tried to add duplicate super var ${newVar.name} with different type: ${newVar.type} instead of ${existingVar.type}.`
);
}
if (existingVar.value !== newVar.value) {
throw new Error(
`Tried to add duplicate super var ${newVar.name} with different value: ${newVar.value} instead of ${existingVar.value}.`
);
}
return false; // No need to add, already exists
}
}
trait.superVariables.push(newVar);
return true;
}

addFunction(baseTrait: BaseImplementedTrait, fn: BaseFunction): ContractFunction {
const t = this.addImplementedTrait(baseTrait);

Expand Down
2 changes: 1 addition & 1 deletion packages/core-cairo/src/custom.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ Generated by [AVA](https://avajs.dev).
use openzeppelin::upgrades::interface::IUpgradeable;␊
use starknet::ClassHash;␊
use starknet::ContractAddress;␊
use super::{UPGRADER_ROLE};␊
use super::UPGRADER_ROLE;␊
component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊
component!(path: SRC5Component, storage: src5, event: SRC5Event);␊
Expand Down
Binary file modified packages/core-cairo/src/custom.test.ts.snap
Binary file not shown.
67 changes: 50 additions & 17 deletions packages/core-cairo/src/erc1155.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@ import { erc1155 } from '.';

import { buildERC1155, ERC1155Options } from './erc1155';
import { printContract } from './print';
import { royaltyInfoOptions } from './set-royalty-info';

const NAME = 'MyToken';
const CUSTOM_NAME = 'CustomToken';
const BASE_URI = 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/';

const allFeaturesON: Partial<ERC1155Options> = {
mintable: true,
burnable: true,
pausable: true,
royaltyInfo: royaltyInfoOptions.enabledDefault,
upgradeable: true
} as const;

function testERC1155(title: string, opts: Partial<ERC1155Options>) {
test(title, t => {
const c = buildERC1155({
name: 'MyToken',
baseUri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/',
name: NAME,
baseUri: BASE_URI,
...opts,
});
t.snapshot(printContract(c));
Expand All @@ -18,10 +31,10 @@ function testERC1155(title: string, opts: Partial<ERC1155Options>) {
/**
* Tests external API for equivalence with internal API
*/
function testAPIEquivalence(title: string, opts?: ERC1155Options) {
function testAPIEquivalence(title: string, opts?: ERC1155Options) {
test(title, t => {
t.is(erc1155.print(opts), printContract(buildERC1155({
name: 'MyToken',
name: NAME,
baseUri: '',
...opts,
})));
Expand Down Expand Up @@ -59,33 +72,51 @@ testERC1155('mintable + roles', {
access: 'roles',
});

testERC1155('royalty info disabled', {
royaltyInfo: royaltyInfoOptions.disabled
});

testERC1155('royalty info enabled default + ownable', {
royaltyInfo: royaltyInfoOptions.enabledDefault,
access: 'ownable'
});

testERC1155('royalty info enabled default + roles', {
royaltyInfo: royaltyInfoOptions.enabledDefault,
access: 'roles'
});

testERC1155('royalty info enabled custom + ownable', {
royaltyInfo: royaltyInfoOptions.enabledCustom,
access: 'ownable'
});

testERC1155('royalty info enabled custom + roles', {
royaltyInfo: royaltyInfoOptions.enabledCustom,
access: 'roles'
});

testERC1155('full non-upgradeable', {
mintable: true,
...allFeaturesON,
access: 'roles',
burnable: true,
pausable: true,
upgradeable: false,
});

testERC1155('full upgradeable', {
mintable: true,
...allFeaturesON,
access: 'roles',
burnable: true,
pausable: true,
upgradeable: true,
});

testAPIEquivalence('API default');

testAPIEquivalence('API basic', { name: 'CustomToken', baseUri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/' });
testAPIEquivalence('API basic', { name: CUSTOM_NAME, baseUri: BASE_URI });

testAPIEquivalence('API full upgradeable', {
name: 'CustomToken',
baseUri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/',
mintable: true,
...allFeaturesON,
name: CUSTOM_NAME,
baseUri: BASE_URI,
access: 'roles',
burnable: true,
pausable: true,
upgradeable: true,
});

Expand All @@ -98,6 +129,8 @@ test('API isAccessControlRequired', async t => {
t.is(erc1155.isAccessControlRequired({ updatableUri: false, pausable: true }), true);
t.is(erc1155.isAccessControlRequired({ updatableUri: false, upgradeable: true }), true);
t.is(erc1155.isAccessControlRequired({ updatableUri: true }), true);
t.is(erc1155.isAccessControlRequired({ updatableUri: false}), false);
t.is(erc1155.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledDefault }), true);
t.is(erc1155.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledCustom }), true);
t.is(erc1155.isAccessControlRequired({ updatableUri: false }), false);
t.is(erc1155.isAccessControlRequired({}), true); // updatableUri is true by default
});
Loading

0 comments on commit 2bf262c

Please sign in to comment.