Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuel Mint support Part 1 - Implement HyperFuel query selection for Mint receipts #214

Merged
merged 11 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,11 @@ jobs:
pnpm hardhat compile --verbose
pnpm res:build

- name: test_codegen test TS types
if: steps.changes.outputs.testChanges == 'true'
working-directory: scenarios/test_codegen
run: pnpm ts:test

- name: test_codegen test
if: steps.changes.outputs.testChanges == 'true'
working-directory: scenarios/test_codegen
run: |
pnpm ts:test
pnpm test

- name: erc20_multichain_factory build
Expand All @@ -157,4 +153,5 @@ jobs:
if: steps.changes.outputs.testChanges == 'true'
working-directory: scenarios/fuel_test
run: |
pnpm ts:test
pnpm test
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ scenarios/**/*.res.js
scenarios/**/*.gen.ts
scenarios/**/lib/*
scenarios/**/node_modules/*
scenarios/**/generated
4 changes: 2 additions & 2 deletions codegenerator/cli/npm/envio/fuel.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@
"type": "object",
"properties": {
"name": {
"description": "A reference to a struct in the ABI or a unique name for the provided log_id",
"description": "Name of the event in the HyperIndex generated code",
"type": "string"
},
"logId": {
"description": "A reference to a log_id in the ABI",
"description": "An identifier of a logged type from ABI. Used for indexing LogData receipts. The option can be omitted when the event name matches the logged struct/enum name.",
"type": [
"string",
"null"
Expand Down
9 changes: 4 additions & 5 deletions codegenerator/cli/src/config_parsing/human_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,13 +525,12 @@ pub mod fuel {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct EventConfig {
#[schemars(
description = "A reference to a struct in the ABI or a unique name for the provided \
log_id"
)]
#[schemars(description = "Name of the event in the HyperIndex generated code")]
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[schemars(description = "A reference to a log_id in the ABI")]
#[schemars(
description = "An identifier of a logged type from ABI. Used for indexing LogData receipts. The option can be omitted when the event name matches the logged struct/enum name."
)]
pub log_id: Option<String>,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,28 @@ let registerContractHandlers = (
{{#with chain_config.network_config.hyperfuel_config as | hyperfuel_config |}}
module(HyperFuelWorker.Make({
let chain = chain
let contracts = contracts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally to get rid of the old contract config

let endpointUrl = "{{hyperfuel_config.endpoint_url}}"
let eventModLookup =
contracts
->Belt.Array.flatMap(contract => contract.events)
->EventModLookup.fromArrayOrThrow(~chain)
let contracts: array<HyperFuelWorker.contract> = [
{{#each chain_config.codegen_contracts as | contract |}}
{
name: "{{contract.name.capitalized}}",
events: [
{{#each contract.events as | event |}}
{
name: "{{event.name.capitalized}}",
logId: Types.{{contract.name.capitalized}}.{{event.name.capitalized}}.sighash,
{{!-- mint: {{#if event.mint}}true{{else}}false{{/if}}, --}}
isWildcard: (Types.{{contract.name.capitalized}}.{{event.name.capitalized}}.handlerRegister->Types.HandlerTypes.Register.getEventOptions).isWildcard,
},
{{/each}}
]
},
{{/each}}
]
}))
{{/with}}
{{/if}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ let updateEntityIndicesMockDb = (
->Array.forEach(((fieldName, fieldValue)) => {
let index = TableIndices.Index.makeSingleEq(~fieldName, ~fieldValue)
mockDbTable->InMemoryTable.Entity.addIdToIndex(~index, ~entityId)
entityIndices->InMemoryTable.StdSet.add(index)->ignore
entityIndices->Utils.Set.add(index)->ignore
})
}

Expand Down Expand Up @@ -152,7 +152,7 @@ let makeStoreOperatorEntity = (
let store = cloned->getStore
let entityIndices = switch store.table->InMemoryTable.get(key) {
| Some({entityIndices}) => entityIndices
| None => InMemoryTable.StdSet.make()
| None => Utils.Set.make()
}
store->InMemoryTable.Entity.deleteEntityFromIndices(~entityId=key, ~entityIndices)
store.table.dict->deleteDictKey(key)
Expand Down Expand Up @@ -322,7 +322,7 @@ let executeRowsEntity = (
mockDbTable.table.dict->deleteDictKey(entityId)
mockDbTable->InMemoryTable.Entity.deleteEntityFromIndices(
~entityId,
~entityIndices=InMemoryTable.StdSet.make(),
~entityIndices=Utils.Set.make(),
)
| InitialReadFromDb(NotSet) => ()
}
Expand Down
46 changes: 23 additions & 23 deletions codegenerator/cli/templates/static/codegen/src/InMemoryTable.res
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
module StdSet = Set

external arrayFromSet: StdSet.t<'a> => array<'a> = "Array.from"
open Belt

type t<'key, 'val> = {
Expand All @@ -24,13 +21,13 @@ let clone = (self: t<'key, 'val>) => {

module Entity = {
type relatedEntityId = Types.id
type indexWithRelatedIds = (TableIndices.Index.t, StdSet.t<relatedEntityId>)
type indexWithRelatedIds = (TableIndices.Index.t, Utils.Set.t<relatedEntityId>)
type indicesSerializedToValue = t<TableIndices.Index.t, indexWithRelatedIds>
type indexFieldNameToIndices = t<TableIndices.Index.t, indicesSerializedToValue>

type entityWithIndices<'entity> = {
entityRow: Types.inMemoryStoreRowEntity<'entity>,
entityIndices: StdSet.t<TableIndices.Index.t>,
entityIndices: Utils.Set.t<TableIndices.Index.t>,
}
type t<'entity> = {
table: t<Types.id, entityWithIndices<'entity>>,
Expand All @@ -39,7 +36,7 @@ module Entity = {

let makeIndicesSerializedToValue = (
~index,
~relatedEntityIds=StdSet.make(),
~relatedEntityIds=Utils.Set.make(),
): indicesSerializedToValue => {
let empty = make(~hash=TableIndices.Index.toString)
empty->set(index, (index, relatedEntityIds))
Expand All @@ -55,18 +52,18 @@ module Entity = {
let updateIndices = (
self: t<'entity>,
~entity: 'entity,
~entityIndices: StdSet.t<TableIndices.Index.t>,
~entityIndices: Utils.Set.t<TableIndices.Index.t>,
) => {
//Remove any invalid indices on entity
entityIndices->StdSet.forEach(index => {
entityIndices->Utils.Set.forEach(index => {
let fieldName = index->TableIndices.Index.getFieldName
let fieldValue =
entity
->(Utils.magic: 'entity => dict<TableIndices.FieldValue.t>)
->Js.Dict.get(fieldName)
->Option.getUnsafe
if !(index->TableIndices.Index.evaluate(~fieldName, ~fieldValue)) {
entityIndices->StdSet.delete(index)->ignore
entityIndices->Utils.Set.delete(index)->ignore
}
})

Expand All @@ -85,8 +82,8 @@ module Entity = {
->Array.forEach(((index, relatedEntityIds)) => {
if index->TableIndices.Index.evaluate(~fieldName, ~fieldValue) {
//Add entity id to indices and add index to entity indicies
relatedEntityIds->StdSet.add(Entities.getEntityIdUnsafe(entity))->ignore
entityIndices->StdSet.add(index)->ignore
relatedEntityIds->Utils.Set.add(Entities.getEntityIdUnsafe(entity))->ignore
entityIndices->Utils.Set.add(index)->ignore
}
})
| _ =>
Expand All @@ -98,15 +95,15 @@ module Entity = {
}

let deleteEntityFromIndices = (self: t<'entity>, ~entityId: Entities.id, ~entityIndices) =>
entityIndices->StdSet.forEach(index => {
entityIndices->Utils.Set.forEach(index => {
switch self.fieldNameIndices
->get(index)
->Option.flatMap(get(_, index)) {
| Some((_index, relatedEntityIds)) =>
let _wasRemoved = relatedEntityIds->StdSet.delete(entityId)
let _wasRemoved = relatedEntityIds->Utils.Set.delete(entityId)
| None => () //Unexpected index should exist if it is entityIndices
}
let _wasRemoved = entityIndices->StdSet.delete(index)
let _wasRemoved = entityIndices->Utils.Set.delete(index)
})

let initValue = (
Expand All @@ -123,7 +120,7 @@ module Entity = {
//Only initialize a row in the case where it is none
//or if allowOverWriteEntity is true (used for mockDb in test helpers)
if shouldWriteEntity {
let entityIndices = StdSet.make()
let entityIndices = Utils.Set.make()
let initialStoreRow: Types.inMemoryStoreRowEntity<'entity> = switch entity {
| Some(entity) =>
//update table indices in the case where there
Expand Down Expand Up @@ -178,7 +175,7 @@ module Entity = {
latest: entityUpdate,
history: [],
})
{entityRow, entityIndices: StdSet.make()}
{entityRow, entityIndices: Utils.Set.make()}
}
switch entityUpdate.entityUpdateAction {
| Set(entity) => inMemTable->updateIndices(~entity, ~entityIndices)
Expand Down Expand Up @@ -215,7 +212,7 @@ module Entity = {
->Option.map(((_index, relatedEntityIds)) => {
let res =
relatedEntityIds
->arrayFromSet
->Utils.Set.toArray
->Array.keepMap(entityId => inMemTable->get(entityId)->Utils.Option.flatten)
res
})
Expand All @@ -229,7 +226,7 @@ module Entity = {

let addEmptyIndex = (inMemTable: t<'entity>, ~index) => {
let fieldName = index->TableIndices.Index.getFieldName
let relatedEntityIds = StdSet.make()
let relatedEntityIds = Utils.Set.make()

inMemTable.table
->values
Expand All @@ -241,8 +238,8 @@ module Entity = {
->(Utils.magic: 'entity => dict<TableIndices.FieldValue.t>)
->Js.Dict.unsafeGet(fieldName)
if index->TableIndices.Index.evaluate(~fieldName, ~fieldValue) {
let _ = row.entityIndices->StdSet.add(index)
let _ = relatedEntityIds->StdSet.add(entity->Entities.getEntityIdUnsafe)
let _ = row.entityIndices->Utils.Set.add(index)
let _ = relatedEntityIds->Utils.Set.add(entity->Entities.getEntityIdUnsafe)
}
| None => ()
}
Expand All @@ -266,13 +263,16 @@ module Entity = {
| None =>
inMemTable.fieldNameIndices->setRow(
index,
makeIndicesSerializedToValue(~index, ~relatedEntityIds=StdSet.make()->StdSet.add(entityId)),
makeIndicesSerializedToValue(
~index,
~relatedEntityIds=Utils.Set.make()->Utils.Set.add(entityId),
),
)
| Some(indicesSerializedToValue) =>
switch indicesSerializedToValue->getRow(index) {
| None =>
indicesSerializedToValue->setRow(index, (index, StdSet.make()->StdSet.add(entityId)))
| Some((_index, relatedEntityIds)) => relatedEntityIds->StdSet.add(entityId)->ignore
indicesSerializedToValue->setRow(index, (index, Utils.Set.make()->Utils.Set.add(entityId)))
| Some((_index, relatedEntityIds)) => relatedEntityIds->Utils.Set.add(entityId)->ignore
}
}

Expand Down
105 changes: 91 additions & 14 deletions codegenerator/cli/templates/static/codegen/src/Utils.res
Original file line number Diff line number Diff line change
Expand Up @@ -219,21 +219,98 @@ module Schema = {
let coerceToJsonPgType = schema => {
schema->S.preprocess(s => {
switch s.schema->S.classify {
| Literal(Null(_)) => {serializer: _ => %raw(`"null"`)}
| Null(_)
| Bool => {serializer: unknown => {
if unknown === %raw(`null`) {
%raw(`"null"`)
} else if unknown === %raw(`false`) {
%raw(`"false"`)
} else if unknown === %raw(`true`) {
%raw(`"true"`)
} else {
unknown
}
}}
| _ => {}
| Literal(Null(_)) => {serializer: _ => %raw(`"null"`)}
| Null(_)
| Bool => {
serializer: unknown => {
if unknown === %raw(`null`) {
%raw(`"null"`)
} else if unknown === %raw(`false`) {
%raw(`"false"`)
} else if unknown === %raw(`true`) {
%raw(`"true"`)
} else {
unknown
}
},
}
| _ => {}
}
})
}
}

module Set = {
type t<'value>

/*
* Constructor
*/
@ocaml.doc("Creates a new `Set` object.") @new
external make: unit => t<'value> = "Set"

@ocaml.doc("Creates a new `Set` object.") @new
external fromEntries: array<'value> => t<'value> = "Set"
Comment on lines +242 to +253
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of interest why rebind this whole module? Just to be explicit about what the bindings are?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent the case when you expect it to use the bindings, but then it unexpectedly used Belt version instead


/*
* Instance properties
*/
@ocaml.doc("Returns the number of values in the `Set` object.") @get
external size: t<'value> => int = "size"

/*
* Instance methods
*/
@ocaml.doc("Appends `value` to the `Set` object. Returns the `Set` object with added value.")
@send
external add: (t<'value>, 'value) => t<'value> = "add"

@ocaml.doc("Removes all elements from the `Set` object.") @send
external clear: t<'value> => unit = "clear"

@ocaml.doc(
"Removes the element associated to the `value` and returns a boolean asserting whether an element was successfully removed or not. `Set.prototype.has(value)` will return `false` afterwards."
)
@send
external delete: (t<'value>, 'value) => bool = "delete"

@ocaml.doc(
"Returns a boolean asserting whether an element is present with the given value in the `Set` object or not."
)
@send
external has: (t<'value>, 'value) => bool = "has"

external toArray: t<'a> => array<'a> = "Array.from"

/*
* Iteration methods
*/
/*
/// NOTE - if we need iteration we can add this back - currently it requires the `rescript-js-iterator` library.
@ocaml.doc(
"Returns a new iterator object that yields the **values** for each element in the `Set` object in insertion order."
)
@send
external values: t<'value> => Js_iterator.t<'value> = "values"

@ocaml.doc("An alias for `Set.prototype.values()`.") @send
external keys: t<'value> => Js_iterator.t<'value> = "values"

@ocaml.doc("Returns a new iterator object that contains **an array of [value, value]** for each element in the `Set` object, in insertion order.

This is similar to the [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) object, so that each entry's `key` is the same as its `value` for a `Set`.")
@send
external entries: t<'value> => Js_iterator.t<('value, 'value)> = "entries"
*/
@ocaml.doc(
"Calls `callbackFn` once for each value present in the `Set` object, in insertion order."
)
@send
external forEach: (t<'value>, 'value => unit) => unit = "forEach"

@ocaml.doc(
"Calls `callbackFn` once for each value present in the `Set` object, in insertion order."
)
@send
external forEachWithSet: (t<'value>, ('value, 'value, t<'value>) => unit) => unit = "forEach"
}
15 changes: 14 additions & 1 deletion codegenerator/cli/templates/static/codegen/src/bindings/Fuel.res
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
type receiptType = | @as(6) LogData
// 0 = Call
// 1 = Return,
// 2 = ReturnData,
// 3 = Panic,
// 4 = Revert,
// 5 = Log,
// 6 = LogData,
// 7 = Transfer,
// 8 = Transferout,
// 9 = ScriptResult,
// 10 = MessageOut,
// 11 = Mint,
// 12 = Burn,
type receiptType = | @as(6) LogData | @as(11) Mint | @as(12) Burn

@module("./vendored-fuel-abi-coder.js")
external transpileAbi: Js.Json.t => Ethers.abi = "transpileAbi"
Expand Down
Loading
Loading