Skip to content

Commit

Permalink
Merge pull request #16 from CirclesUBI/20240313-new-contracts
Browse files Browse the repository at this point in the history
20240313 new contracts
  • Loading branch information
jaensen authored Apr 9, 2024
2 parents b211359 + f6d2f03 commit 8e7f717
Show file tree
Hide file tree
Showing 98 changed files with 5,672 additions and 1,410 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports = {
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
project: './tsconfig.base.json',
alwaysTryTypes: true // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
}
}
Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
[submodule "packages/circles-contracts-v2"]
path = packages/circles-contracts-v2
url = https://github.com/CirclesUBI/circles-contracts-v2.git
branch = 20240301-flow-matrix
branch = develop
12 changes: 0 additions & 12 deletions buildContracts.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
#!/bin/bash
# This script is used to build the v1 and v2 contracts.
# The output (especially the ABIs) are used in other sdk packages.
#
# Because the v1 contracts won't build if they're part of a npm workspace,
# we need to remove the workspace before build and then add it back.
# This is ugly and the v1 package should be updated to be compatible with workspaces.

# Make sure v1 and v2 contract code is available
git submodule update --init --recursive --remote

# Remove the v1 package from the workspaces
jq 'del(.workspaces[0])' package.json > temp.package.json || exit
mv temp.package.json package.json

# Build the v1 contracts
cd ./packages/circles-contracts
npm install @openzeppelin/contracts@^3.4.0-solc-0.7
Expand All @@ -21,10 +13,6 @@ npm install @circles/safe-contracts@=1.0.14
forge build
cd ../..

# Insert the v1 package back into the workspaces
jq '.workspaces |= if index("packages/circles-contracts") then . else ["packages/circles-contracts"] + . end' package.json > temp.package.json
mv temp.package.json package.json

# Build the v2 contracts
cd ./packages/circles-contracts-v2
forge build
132 changes: 132 additions & 0 deletions codegen/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions codegen/src/generateCallDecoders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getInputName } from './utils.js';

const generateGenericDecodeMethod = (contractName: string, output: OutputBuffer, functionFragments: FunctionFragment[], functionInputTypeMap: Map<string, string | undefined>) => {
return `
decode(callData: string): inputTypes.${contractName}FunctionInputs {
decode(callData: string): { name: string, inputs: inputTypes.${contractName}FunctionInputs} {
if (callData.length < 10) {
throw new Error(\`Call data too short to encode a methodId: \${callData}\`);
}
Expand All @@ -16,20 +16,27 @@ const generateGenericDecodeMethod = (contractName: string, output: OutputBuffer,
}
if (functionFragment.inputs.length === 0) {
return <inputTypes.NoInputs>[];
return {
name: functionFragment.name,
inputs: <inputTypes.NoInputs>[]
};
}
let decoded: any;
switch (<${contractName}FunctionName>functionFragment.name) {
${functionFragments.map((functionAbi) => {
const typeName = functionInputTypeMap.get(functionAbi.name);
if (!typeName) return '';
return ` case '${functionAbi.name}':
return this.decode${typeName}(callData);
return ` case '${functionAbi.name}': decoded = this.decode${typeName}(callData); break;
`;
}).join('')}
default:
throw new Error(\`Unknown function name '\${functionFragment.name}' the code is out of sync with the ABI\`);
}
return {
name: functionFragment.name,
inputs: decoded
};
}
`;
};
Expand Down
15 changes: 9 additions & 6 deletions codegen/src/generateContractWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { OutputBuffer } from './outputBuffer.js';
import { generateDecoder, getInputName, solidityToTypeScriptTypes } from './utils.js';
import { FunctionFragment, ParamType } from 'ethers';
import { EventFragment, FunctionFragment, ParamType } from 'ethers';

export const generateContractWrapper = (contractName: string, output: OutputBuffer, functionFragments: FunctionFragment[]): void => {
export const generateContractWrapper = (contractName: string, output: OutputBuffer, functionFragments: FunctionFragment[], eventFragments: EventFragment[]): void => {
const viewFunctionFragments = functionFragments.filter(f => f.stateMutability === 'view' || f.stateMutability === 'pure');
const transactionFunctionFragments = functionFragments.filter(f => f.stateMutability !== 'view' && f.stateMutability !== 'pure');

Expand Down Expand Up @@ -60,28 +60,31 @@ return [${outputs.map((output, index) => `${generateDecoder(output.type, `decode
`).join('\n');

const generateClass = (viewFunctions: string, transactionFunctions: string) =>
`import { ${contractName}Calls } from './${contractName}Encoders';
import { Parsed${contractName}Event, ${contractName}Event, ${contractName}Events } from './${contractName}Events';
`import { ${contractName}Calls } from './${contractName}Encoders';`
+ (eventFragments.length > 0 ? `
import { Parsed${contractName}Event, ${contractName}Event, ${contractName}Events } from './${contractName}Events';` : '') + `
import { ethers, TransactionRequest, TransactionResponse } from 'ethers';
import { Observable } from "./common";
export class ${contractName || 'Wrapper'} {
readonly address: string;
private readonly provider: ethers.Provider;
` + (eventFragments.length > 0 ? `
private readonly eventDecoder: ${contractName}Events = new ${contractName}Events();
public readonly events: Observable<Parsed${contractName}Event<${contractName}Event>>;
private readonly emitEvent: (event: Parsed${contractName}Event<${contractName}Event>) => void;
private readonly emitEvent: (event: Parsed${contractName}Event<${contractName}Event>) => void;` : '') + `
private callEncoder: ${contractName}Calls = new ${contractName}Calls();
constructor(provider: ethers.Provider, address: string) {
this.provider = provider;
this.address = address;
` + (eventFragments.length > 0 ? `
const events = Observable.create<Parsed${contractName}Event<${contractName}Event>>();
this.events = events.property;
this.emitEvent = events.emit;
` : '') + `
}
private sendTransaction(request: TransactionRequest) : Promise<TransactionResponse> {
Expand Down
14 changes: 9 additions & 5 deletions codegen/src/generateEventDecoders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { solidityToTypeScriptTypes } from './utils.js';

const generateEventTypesAndParsers = (eventFragments: EventFragment[]): {
eventTypes: string,
parsers: string
parsers: string,
eventTypeNames: string[]
} => {
let eventTypes = '';
let parsers = '';

const eventTypeNames: string[] = [];
eventFragments.forEach(eventFragment => {
const eventTypeFields = eventFragment.inputs.map((input: any) => {
const tsType = solidityToTypeScriptTypes(input.type);
Expand All @@ -17,6 +18,7 @@ const generateEventTypesAndParsers = (eventFragments: EventFragment[]): {

const eventName = eventFragment.name;
const typeName = `${eventName}Event`;
eventTypeNames.push(typeName);
eventTypes += `export type ${typeName} = Event & {\n ${eventTypeFields}\n};\n\n`;

// Utilize the existing type mapping functions for conversion logic
Expand All @@ -40,12 +42,12 @@ const generateEventTypesAndParsers = (eventFragments: EventFragment[]): {
parsers += `const parse${typeName} = (log: ethers.LogDescription): ${typeName} => ({\n ${params}\n});\n\n`;
});

return { eventTypes, parsers };
return { eventTypes, parsers, eventTypeNames };
};


export const generateEventDecoders = (contractName: string, output: OutputBuffer, eventFragments: EventFragment[]): void => {
const { eventTypes, parsers } = generateEventTypesAndParsers(eventFragments);
export const generateEventDecoders = (contractName: string, output: OutputBuffer, eventFragments: EventFragment[]): string[] => {
const { eventTypes, parsers, eventTypeNames } = generateEventTypesAndParsers(eventFragments);
const decoderCases = eventFragments.map(eventAbi => {
const eventName = eventAbi.name;
const typeName = `${eventName}Event`;
Expand Down Expand Up @@ -92,4 +94,6 @@ export class ${contractName}Events implements EventDecoder {
};
}
}`);

return eventTypeNames
};
6 changes: 6 additions & 0 deletions codegen/src/generateFunctionInputTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { getInputName, solidityToTypeScriptTypes } from './utils.js';

const generateTypeDefinition = (functionAbi: any, typeName: string): string => {
const inputs = functionAbi.inputs.map((input: any, index: number) => {
if (input.components) {
// TODO: Support structs
/*
*/
}
const tsType = solidityToTypeScriptTypes(input.type);
const paramName = getInputName(input, index);
return `${paramName}: ${tsType};`;
Expand Down
19 changes: 11 additions & 8 deletions codegen/src/generateIndex.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { OutputBuffer } from './outputBuffer.js';

export const generateIndexFile = (contractName: string, output: OutputBuffer) => {
output.writeLine(`import { Event, ParsedEvent, EventDecoder } from './common';
export const generateIndexFile = (contractName: string, eventTypeNames: string[], generateCommon: boolean, output: OutputBuffer) => {
output.writeLine((generateCommon ? `import { Event, ParsedEvent, EventDecoder } from './common';` : ``) + `
import { ${contractName}Decoders } from './${contractName}Decoders';
import * as inputTypes from './${contractName}FunctionInputTypes';
import * as ${contractName}InputTypes from './${contractName}FunctionInputTypes';
import { ${contractName}FunctionName, ${contractName}FunctionNames } from './${contractName}FunctionNames';
import { ${contractName}Calls } from './${contractName}Encoders';
import { ${contractName}Events } from './${contractName}Events';
import { ${contractName == '' || !contractName ? 'Wrapper' : contractName} } from './${contractName == '' || !contractName ? 'Wrapper' : contractName}';
` + (eventTypeNames.length > 0 ? `
import { ${contractName}Events, ${contractName}Event ${eventTypeNames.length > 0 ? ', ' + eventTypeNames.join(', ') : ''} } from './${contractName}Events';` : '') + `
import { ${(contractName == '' || !contractName) ? 'Wrapper' : contractName} } from './${contractName == '' || !contractName ? 'Wrapper' : contractName + 'Wrapper'}';
export {
Event,
` + (generateCommon ? `Event,
ParsedEvent,
EventDecoder,
EventDecoder,` : ``) + `
${contractName}Decoders,
inputTypes as ${contractName}InputTypes,
${contractName}InputTypes,
${contractName}FunctionName,
${contractName}FunctionNames,
${contractName}Calls,
` + (eventTypeNames.length > 0 ? `
${contractName}Events,
${contractName}Event${eventTypeNames.length > 0 ? ', ' + eventTypeNames.join(', ') + ',' : ''}` : '') + `
${contractName == '' || !contractName ? 'Wrapper' : contractName},
};`);
};
Loading

0 comments on commit 8e7f717

Please sign in to comment.