envio 2.18.0 → 2.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts ADDED
@@ -0,0 +1,144 @@
1
+ export type {
2
+ logger as Logger,
3
+ effect as Effect,
4
+ effectContext as EffectContext,
5
+ effectArgs as EffectArgs,
6
+ effectOptions as EffectOptions,
7
+ } from "./src/Envio.gen.ts";
8
+ export type { EffectCaller } from "./src/Types.ts";
9
+
10
+ import type {
11
+ effect as Effect,
12
+ effectArgs as EffectArgs,
13
+ } from "./src/Envio.gen.ts";
14
+
15
+ import { schema as bigDecimalSchema } from "./src/bindings/BigDecimal.gen.ts";
16
+ import * as Sury from "rescript-schema";
17
+
18
+ type UnknownToOutput<T> = T extends Sury.Schema<unknown>
19
+ ? Sury.Output<T>
20
+ : T extends (...args: any[]) => any
21
+ ? T
22
+ : T extends unknown[]
23
+ ? { [K in keyof T]: UnknownToOutput<T[K]> }
24
+ : T extends { [k in keyof T]: unknown }
25
+ ? Flatten<
26
+ {
27
+ [k in keyof T as HasUndefined<UnknownToOutput<T[k]>> extends true
28
+ ? k
29
+ : never]?: UnknownToOutput<T[k]>;
30
+ } & {
31
+ [k in keyof T as HasUndefined<UnknownToOutput<T[k]>> extends true
32
+ ? never
33
+ : k]: UnknownToOutput<T[k]>;
34
+ }
35
+ >
36
+ : T;
37
+
38
+ type UnknownToInput<T> = T extends Sury.Schema<unknown>
39
+ ? Sury.Input<T>
40
+ : T extends (...args: any[]) => any
41
+ ? T
42
+ : T extends unknown[]
43
+ ? { [K in keyof T]: UnknownToInput<T[K]> }
44
+ : T extends { [k in keyof T]: unknown }
45
+ ? Flatten<
46
+ {
47
+ [k in keyof T as HasUndefined<UnknownToInput<T[k]>> extends true
48
+ ? k
49
+ : never]?: UnknownToInput<T[k]>;
50
+ } & {
51
+ [k in keyof T as HasUndefined<UnknownToInput<T[k]>> extends true
52
+ ? never
53
+ : k]: UnknownToInput<T[k]>;
54
+ }
55
+ >
56
+ : T;
57
+
58
+ type HasUndefined<T> = [T] extends [undefined]
59
+ ? true
60
+ : undefined extends T
61
+ ? true
62
+ : false;
63
+
64
+ // Utility to flatten the type into a single object
65
+ type Flatten<T> = T extends object
66
+ ? { [K in keyof T as T[K] extends never ? never : K]: T[K] }
67
+ : T;
68
+
69
+ // All the type gymnastics with generics to be able to
70
+ // define schema without an additional `S.schema` call in TS:
71
+ // createEffect({
72
+ // input: undefined,
73
+ // })
74
+ // Instead of:
75
+ // createEffect({
76
+ // input: S.schema(undefined),
77
+ // })
78
+ // Or for objects:
79
+ // createEffect({
80
+ // input: {
81
+ // foo: S.string,
82
+ // },
83
+ // })
84
+ // Instead of:
85
+ // createEffect({
86
+ // input: S.schema({
87
+ // foo: S.string,
88
+ // }),
89
+ // })
90
+ // The behaviour is inspired by Sury code:
91
+ // https://github.com/DZakh/sury/blob/551f8ee32c1af95320936d00c086e5fb337f59fa/packages/sury/src/S.d.ts#L344C1-L355C50
92
+ export function experimental_createEffect<
93
+ IS,
94
+ OS,
95
+ I = UnknownToInput<IS>,
96
+ O = UnknownToOutput<OS>,
97
+ // A hack to enforce that the inferred return type
98
+ // matches the output schema type
99
+ R extends O = O
100
+ >(
101
+ options: {
102
+ /** The name of the effect. Used for logging and debugging. */
103
+ readonly name: string;
104
+ /** The input schema of the effect. */
105
+ readonly input: IS;
106
+ /** The output schema of the effect. */
107
+ readonly output: OS;
108
+ },
109
+ handler: (args: EffectArgs<I>) => Promise<R>
110
+ ): Effect<I, O>;
111
+
112
+ // Important! Should match the index.js file
113
+ export declare namespace S {
114
+ export type Output<T> = Sury.Output<T>;
115
+ export type Input<T> = Sury.Input<T>;
116
+ export type Schema<Output, Input = unknown> = Sury.Schema<Output, Input>;
117
+ export const string: typeof Sury.string;
118
+ export const jsonString: typeof Sury.jsonString;
119
+ export const boolean: typeof Sury.boolean;
120
+ export const int32: typeof Sury.int32;
121
+ export const number: typeof Sury.number;
122
+ export const bigint: typeof Sury.bigint;
123
+ export const never: typeof Sury.never;
124
+ export const union: typeof Sury.union;
125
+ export const object: typeof Sury.object;
126
+ // Might change in a near future
127
+ // export const custom: typeof Sury.custom;
128
+ // Don't expose recursive for now, since it's too advanced
129
+ // export const recursive: typeof Sury.recursive;
130
+ export const transform: typeof Sury.transform;
131
+ export const refine: typeof Sury.refine;
132
+ export const schema: typeof Sury.schema;
133
+ export const record: typeof Sury.record;
134
+ export const array: typeof Sury.array;
135
+ export const tuple: typeof Sury.tuple;
136
+ export const merge: typeof Sury.merge;
137
+ export const optional: typeof Sury.optional;
138
+ export const nullable: typeof Sury.nullable;
139
+ export const bigDecimal: typeof bigDecimalSchema;
140
+ export const unknown: typeof Sury.unknown;
141
+ // Nullish type will change in "sury@10"
142
+ // export const nullish: typeof Sury.nullish;
143
+ export const assertOrThrow: typeof Sury.assertOrThrow;
144
+ }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "v2.18.0",
3
+ "version": "v2.19.1",
4
4
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
5
5
  "bin": "./bin.js",
6
- "types": "index.d.ts",
6
+ "main": "./index.js",
7
+ "types": "./index.d.ts",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/enviodev/hyperindex.git"
@@ -24,10 +25,10 @@
24
25
  },
25
26
  "homepage": "https://envio.dev",
26
27
  "optionalDependencies": {
27
- "envio-linux-x64": "v2.18.0",
28
- "envio-linux-arm64": "v2.18.0",
29
- "envio-darwin-x64": "v2.18.0",
30
- "envio-darwin-arm64": "v2.18.0"
28
+ "envio-linux-x64": "v2.19.1",
29
+ "envio-linux-arm64": "v2.19.1",
30
+ "envio-darwin-x64": "v2.19.1",
31
+ "envio-darwin-arm64": "v2.19.1"
31
32
  },
32
33
  "dependencies": {
33
34
  "@envio-dev/hypersync-client": "0.6.3",
@@ -40,6 +41,7 @@
40
41
  "evm.schema.json",
41
42
  "fuel.schema.json",
42
43
  "rescript.json",
44
+ "index.d.ts",
43
45
  "src",
44
46
  "!src/**/*.bs.js"
45
47
  ]
package/src/Envio.gen.ts CHANGED
@@ -3,6 +3,27 @@
3
3
  /* eslint-disable */
4
4
  /* tslint:disable */
5
5
 
6
+ import type {EffectContext as $$effectContext} from './Types.ts';
7
+
8
+ import type {Effect as $$effect} from './Types.ts';
9
+
6
10
  import type {Logger as $$logger} from './Types.ts';
7
11
 
12
+ import type {S_t as RescriptSchema_S_t} from './RescriptSchema.gen';
13
+
8
14
  export type logger = $$logger;
15
+
16
+ export type effect<input,output> = $$effect<input,output>;
17
+
18
+ export type effectOptions<input,output> = {
19
+ /** The name of the effect. Used for logging and debugging. */
20
+ readonly name: string;
21
+ /** The input schema of the effect. */
22
+ readonly input: RescriptSchema_S_t<input>;
23
+ /** The output schema of the effect. */
24
+ readonly output: RescriptSchema_S_t<output>
25
+ };
26
+
27
+ export type effectContext = $$effectContext;
28
+
29
+ export type effectArgs<input> = { readonly input: input; readonly context: effectContext };
package/src/Envio.res CHANGED
@@ -10,3 +10,41 @@ type logger = {
10
10
  error: 'params. (string, ~params: {..} as 'params=?) => unit,
11
11
  errorWithExn: (string, exn) => unit,
12
12
  }
13
+
14
+ @@warning("-30") // Duplicated type names (input)
15
+ @genType.import(("./Types.ts", "Effect"))
16
+ type rec effect<'input, 'output>
17
+ @genType
18
+ and effectOptions<'input, 'output> = {
19
+ /** The name of the effect. Used for logging and debugging. */
20
+ name: string,
21
+ /** The input schema of the effect. */
22
+ input: S.t<'input>,
23
+ /** The output schema of the effect. */
24
+ output: S.t<'output>,
25
+ }
26
+ @genType.import(("./Types.ts", "EffectContext"))
27
+ and effectContext = {
28
+ log: logger,
29
+ effect: 'input 'output. (effect<'input, 'output>, 'input) => promise<'output>,
30
+ }
31
+ @genType
32
+ and effectArgs<'input> = {
33
+ input: 'input,
34
+ context: effectContext,
35
+ }
36
+ @@warning("+30")
37
+
38
+ let experimental_createEffect = (
39
+ options: effectOptions<'input, 'output>,
40
+ handler: effectArgs<'input> => promise<'output>,
41
+ ) => {
42
+ {
43
+ name: options.name,
44
+ handler: handler->(
45
+ Utils.magic: (effectArgs<'input> => promise<'output>) => Internal.effectArgs => promise<
46
+ Internal.effectOutput,
47
+ >
48
+ ),
49
+ }->(Utils.magic: Internal.effect => effect<'input, 'output>)
50
+ }
@@ -37,6 +37,7 @@ export type genericHandlerWithLoader<loader,handler,eventFilters> = {
37
37
  readonly handler: handler;
38
38
  readonly wildcard?: boolean;
39
39
  readonly eventFilters?: eventFilters;
40
+ /** @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration. */
40
41
  readonly preRegisterDynamicContracts?: boolean
41
42
  };
42
43
 
package/src/Internal.res CHANGED
@@ -61,6 +61,9 @@ type genericHandlerWithLoader<'loader, 'handler, 'eventFilters> = {
61
61
  handler: 'handler,
62
62
  wildcard?: bool,
63
63
  eventFilters?: 'eventFilters,
64
+ /**
65
+ @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration.
66
+ */
64
67
  preRegisterDynamicContracts?: bool,
65
68
  }
66
69
 
@@ -73,10 +76,11 @@ type eventConfig = private {
73
76
  name: string,
74
77
  contractName: string,
75
78
  isWildcard: bool,
79
+ // Whether the event has an event filter which uses addresses
80
+ filterByAddresses: bool,
76
81
  // Usually always false for wildcard events
77
82
  // But might be true for wildcard event with dynamic event filter by addresses
78
83
  dependsOnAddresses: bool,
79
- preRegisterDynamicContracts: bool,
80
84
  loader: option<loader>,
81
85
  handler: option<handler>,
82
86
  contractRegister: option<contractRegister>,
@@ -130,10 +134,6 @@ type eventItem = {
130
134
  blockNumber: int,
131
135
  logIndex: int,
132
136
  event: event,
133
- //Default to false, if an event needs to
134
- //be reprocessed after it has loaded dynamic contracts
135
- //This gets set to true and does not try and reload events
136
- hasRegisteredDynamicContracts?: bool,
137
137
  // Reuse logger object for event
138
138
  mutable loggerCache?: Pino.t,
139
139
  }
@@ -161,6 +161,19 @@ let fuelTransferParamsSchema = S.schema(s => {
161
161
 
162
162
  type entity = private {id: string}
163
163
 
164
+ type effectInput
165
+ type effectOutput
166
+ type effectContext
167
+ type effectArgs = {
168
+ input: effectInput,
169
+ context: effectContext,
170
+ cacheKey: string,
171
+ }
172
+ type effect = {
173
+ name: string,
174
+ handler: effectArgs => promise<effectOutput>,
175
+ }
176
+
164
177
  @genType.import(("./Types.ts", "Invalid"))
165
178
  type noEventFilters
166
179
 
@@ -106,6 +106,11 @@ let call = (
106
106
  ~key,
107
107
  ~load,
108
108
  ~hasher,
109
+ /*
110
+ Whether the call should be grouped
111
+ with the same calls until the next microtask
112
+ or executed immediately
113
+ */
109
114
  ~shouldGroup,
110
115
  ~hasInMemory,
111
116
  ~getUnsafeInMemory,
@@ -59,7 +59,7 @@ let make = (~addresses, ~topicSelections) => {
59
59
 
60
60
  type parsedEventFilters = {
61
61
  getEventFiltersOrThrow: ChainMap.Chain.t => Internal.eventFilters,
62
- dependsOnAddresses: bool,
62
+ filterByAddresses: bool,
63
63
  }
64
64
 
65
65
  let parseEventFiltersOrThrow = {
@@ -74,7 +74,7 @@ let parseEventFiltersOrThrow = {
74
74
  ~topic2=noopGetter,
75
75
  ~topic3=noopGetter,
76
76
  ): parsedEventFilters => {
77
- let dependsOnAddresses = ref(false)
77
+ let filterByAddresses = ref(false)
78
78
  let topic0 = [sighash->EvmTypes.Hex.fromStringUnsafe]
79
79
  let default = {
80
80
  Internal.topic0,
@@ -145,7 +145,7 @@ let parseEventFiltersOrThrow = {
145
145
  "addresses",
146
146
  {
147
147
  get: () => {
148
- dependsOnAddresses := true
148
+ filterByAddresses := true
149
149
  []
150
150
  },
151
151
  },
@@ -154,7 +154,7 @@ let parseEventFiltersOrThrow = {
154
154
  } catch {
155
155
  | _ => ()
156
156
  }
157
- if dependsOnAddresses.contents {
157
+ if filterByAddresses.contents {
158
158
  chain => Internal.Dynamic(
159
159
  addresses => fn({chainId: chain->ChainMap.Chain.toChainId, addresses})->parse,
160
160
  )
@@ -173,7 +173,7 @@ let parseEventFiltersOrThrow = {
173
173
 
174
174
  {
175
175
  getEventFiltersOrThrow,
176
- dependsOnAddresses: dependsOnAddresses.contents,
176
+ filterByAddresses: filterByAddresses.contents,
177
177
  }
178
178
  }
179
179
  }
package/src/Types.ts CHANGED
@@ -20,3 +20,28 @@ export type Logger = {
20
20
  params?: Record<string, unknown> | Error
21
21
  ) => void;
22
22
  };
23
+
24
+ export abstract class Effect<I, O> {
25
+ protected opaque!: I | O;
26
+ }
27
+
28
+ export type EffectCaller = <I, O>(
29
+ effect: Effect<I, O>,
30
+ // This is a hack to make the call complain on undefined
31
+ // when it's not needed, instead of extending the input type.
32
+ // Might be not needed if I misunderstand something in TS.
33
+ input: I extends undefined ? undefined : I
34
+ ) => Promise<O>;
35
+
36
+ export type EffectContext = {
37
+ /**
38
+ * Access the logger instance with event as a context. The logs will be displayed in the console and Envio Hosted Service.
39
+ */
40
+ readonly log: Logger;
41
+ /**
42
+ * Call the provided Effect with the given input.
43
+ * Effects are the best for external calls with automatic deduplication, error handling and caching.
44
+ * Define a new Effect using createEffect outside of the handler.
45
+ */
46
+ readonly effect: EffectCaller;
47
+ };
package/src/Utils.res CHANGED
@@ -70,6 +70,8 @@ module Dict = {
70
70
  */
71
71
  external dangerouslyGetNonOption: (dict<'a>, string) => option<'a> = ""
72
72
 
73
+ let has: (dict<'a>, string) => bool = %raw(`(dict, key) => key in dict`)
74
+
73
75
  let push = (dict, key, value) => {
74
76
  switch dict->dangerouslyGetNonOption(key) {
75
77
  | Some(arr) => arr->Js.Array2.push(value)->ignore
@@ -86,6 +88,9 @@ module Dict = {
86
88
 
87
89
  let merge: (dict<'a>, dict<'a>) => dict<'a> = %raw(`(dictA, dictB) => ({...dictA, ...dictB})`)
88
90
 
91
+ @val
92
+ external mergeInPlace: (dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
93
+
89
94
  let map = (dict, fn) => {
90
95
  let newDict = Js.Dict.empty()
91
96
  let keys = dict->Js.Dict.keys
@@ -103,6 +108,14 @@ module Dict = {
103
108
  }
104
109
  }
105
110
 
111
+ let forEachWithKey = (dict, fn) => {
112
+ let keys = dict->Js.Dict.keys
113
+ for idx in 0 to keys->Js.Array2.length - 1 {
114
+ let key = keys->Js.Array2.unsafe_get(idx)
115
+ fn(key, dict->Js.Dict.unsafeGet(key))
116
+ }
117
+ }
118
+
106
119
  let deleteInPlace: (dict<'a>, string) => unit = %raw(`(dict, key) => {
107
120
  delete dict[key];
108
121
  }
@@ -115,6 +128,8 @@ module Dict = {
115
128
  ) => dict<'a> = %raw(`(dict, key, value) => ({...dict, [key]: value})`)
116
129
 
117
130
  let shallowCopy: dict<'a> => dict<'a> = %raw(`(dict) => ({...dict})`)
131
+
132
+ let size = dict => dict->Js.Dict.keys->Js.Array2.length
118
133
  }
119
134
 
120
135
  module Math = {
@@ -205,6 +220,12 @@ Helper to check if a value exists in an array
205
220
  | _ => false
206
221
  }
207
222
 
223
+ let notEmpty = (arr: array<_>) =>
224
+ switch arr {
225
+ | [] => false
226
+ | _ => true
227
+ }
228
+
208
229
  let awaitEach = async (arr: array<'a>, fn: 'a => promise<unit>) => {
209
230
  for i in 0 to arr->Array.length - 1 {
210
231
  let item = arr[i]
@@ -270,6 +291,9 @@ Helper to check if a value exists in an array
270
291
 
271
292
  @send
272
293
  external flatten: (array<array<'a>>, @as(1) _) => array<'a> = "flat"
294
+
295
+ @send
296
+ external copy: array<'a> => array<'a> = "slice"
273
297
  }
274
298
 
275
299
  module String = {
@@ -467,3 +491,49 @@ module Proxy = {
467
491
  @new
468
492
  external make: ('a, traps<'a>) => 'a = "Proxy"
469
493
  }
494
+
495
+ module Hash = {
496
+ let rec makeOrThrow = (any: 'a): string => {
497
+ switch any->Js.typeof {
498
+ | "string" => any->magic
499
+ | "number" => any->magic->Js.Int.toString
500
+ | "bigint" => any->magic->BigInt.toString
501
+ | "boolean" => any->magic ? "true" : "false"
502
+ | "undefined" => "undefined"
503
+ | "object" =>
504
+ if any === %raw(`null`) {
505
+ "null"
506
+ } else if any->Js.Array2.isArray {
507
+ let any: array<'a> = any->magic
508
+ let hash = ref("[")
509
+ for i in 0 to any->Js.Array2.length - 1 {
510
+ hash := hash.contents ++ any->Js.Array2.unsafe_get(i)->makeOrThrow ++ ","
511
+ }
512
+ hash.contents ++ "]"
513
+ } else {
514
+ let any: dict<'a> = any->magic
515
+ let constructor = any->Js.Dict.unsafeGet("constructor")->magic
516
+ if constructor === %raw(`Object`) {
517
+ let hash = ref("{")
518
+ let keys = any->Js.Dict.keys->Js.Array2.sortInPlace
519
+ for i in 0 to keys->Js.Array2.length - 1 {
520
+ let key = keys->Js.Array2.unsafe_get(i)
521
+ // Ideally should escape and wrap the key in double quotes
522
+ // but since we don't need to decode the hash,
523
+ // it's fine to keep it super simple
524
+ hash := hash.contents ++ key ++ ":" ++ any->Js.Dict.unsafeGet(key)->makeOrThrow ++ ","
525
+ }
526
+ hash.contents ++ "}"
527
+ } else if constructor["name"] === "BigNumber" {
528
+ (any->magic)["toString"]()
529
+ } else {
530
+ Js.Exn.raiseError(`Don't know how to serialize ${(constructor->magic)["name"]}`)
531
+ }
532
+ }
533
+ | "symbol"
534
+ | "function" =>
535
+ (any->magic)["toString"]()
536
+ | typeof => Js.Exn.raiseError(`Don't know how to serialize ${typeof}`)
537
+ }
538
+ }
539
+ }
@@ -3,6 +3,12 @@
3
3
  /* eslint-disable */
4
4
  /* tslint:disable */
5
5
 
6
+ const BigDecimalJS = require('./BigDecimal.bs.js');
7
+
8
+ import type {S_t as RescriptSchema_S_t} from './RescriptSchema.gen';
9
+
6
10
  import type {default as $$t} from 'bignumber.js';
7
11
 
8
12
  export type t = $$t;
13
+
14
+ export const schema: RescriptSchema_S_t<t> = BigDecimalJS.schema as any;
@@ -47,6 +47,7 @@ let one = fromInt(1)
47
47
  @send external decimalPlaces: (t, int) => t = "decimalPlaces"
48
48
 
49
49
  // Serialization
50
+ @genType
50
51
  let schema =
51
52
  S.string
52
53
  ->S.setName("BigDecimal")
@@ -1,115 +0,0 @@
1
- type contractName = string
2
-
3
- // Currently this mapping append only, so we don't need to worry about
4
- // protecting static addresses from de-registration.
5
-
6
- type mapping = {
7
- nameByAddress: dict<contractName>,
8
- addressesByName: dict<Belt.Set.String.t>,
9
- }
10
-
11
- exception AddressRegisteredForMultipleContracts({address: Address.t, names: array<contractName>})
12
-
13
- let addAddress = (map: mapping, ~name: string, ~address: Address.t) => {
14
- switch map.nameByAddress->Utils.Dict.dangerouslyGetNonOption(address->Address.toString) {
15
- | Some(currentName) if currentName != name =>
16
- let logger = Logging.createChild(
17
- ~params={
18
- "address": address->Address.toString,
19
- "existingContract": currentName,
20
- "newContract": name,
21
- },
22
- )
23
- AddressRegisteredForMultipleContracts({
24
- address,
25
- names: [currentName, name],
26
- })->ErrorHandling.mkLogAndRaise(~msg="Address registered for multiple contracts", ~logger)
27
- | _ => ()
28
- }
29
- map.nameByAddress->Js.Dict.set(address->Address.toString, name)
30
-
31
- let oldAddresses =
32
- map.addressesByName
33
- ->Utils.Dict.dangerouslyGetNonOption(name)
34
- ->Belt.Option.getWithDefault(Belt.Set.String.empty)
35
- let newAddresses = oldAddresses->Belt.Set.String.add(address->Address.toString)
36
- map.addressesByName->Js.Dict.set(name, newAddresses)
37
- }
38
-
39
- let getAddresses = (map: mapping, name: string) => {
40
- map.addressesByName->Utils.Dict.dangerouslyGetNonOption(name)
41
- }
42
-
43
- let getName = (map: mapping, address: string) => {
44
- map.nameByAddress->Utils.Dict.dangerouslyGetNonOption(address)
45
- }
46
-
47
- let make = () => {
48
- nameByAddress: Js.Dict.empty(),
49
- addressesByName: Js.Dict.empty(),
50
- }
51
-
52
- let getContractNameFromAddress = (mapping, ~contractAddress: Address.t): option<contractName> => {
53
- mapping->getName(contractAddress->Address.toString)
54
- }
55
-
56
- let stringsToAddresses: array<string> => array<Address.t> = Utils.magic
57
- let keyValStringToAddress: array<(string, string)> => array<(Address.t, string)> = Utils.magic
58
-
59
- let getAddressesFromContractName = (mapping, ~contractName) => {
60
- switch mapping->getAddresses(contractName) {
61
- | Some(addresses) => addresses
62
- | None => Belt.Set.String.empty
63
- }
64
- ->Belt.Set.String.toArray
65
- ->stringsToAddresses
66
- }
67
-
68
- let getAllAddresses = (mapping: mapping) => {
69
- mapping.nameByAddress->Js.Dict.keys->stringsToAddresses
70
- }
71
-
72
- let copy = (mapping: mapping) => {
73
- {
74
- nameByAddress: mapping.nameByAddress->Utils.Dict.shallowCopy,
75
- // Since Belt.Set.String.t is immutable, we can simply do shallow copy here
76
- addressesByName: mapping.addressesByName->Utils.Dict.shallowCopy,
77
- }
78
- }
79
-
80
- let mergeInPlace = (map, ~target) => {
81
- map.nameByAddress
82
- ->Js.Dict.keys
83
- ->Belt.Array.forEach(addr => {
84
- let name = map.nameByAddress->Js.Dict.unsafeGet(addr)
85
- target->addAddress(~address=addr->Address.unsafeFromString, ~name)
86
- })
87
- }
88
-
89
- let fromArray = (nameAddrTuples: array<(Address.t, string)>) => {
90
- let m = make()
91
- nameAddrTuples->Belt.Array.forEach(((address, name)) => m->addAddress(~name, ~address))
92
- m
93
- }
94
-
95
- /**
96
- Creates a new mapping from the previous without the addresses passed in as "addressesToRemove"
97
- */
98
- let removeAddresses = (mapping: mapping, ~addressesToRemove: array<Address.t>) => {
99
- switch addressesToRemove {
100
- | [] => mapping
101
- | _ =>
102
- mapping.nameByAddress
103
- ->Js.Dict.entries
104
- ->Belt.Array.keep(((addr, _name)) => {
105
- let shouldRemove = addressesToRemove->Utils.Array.includes(addr->Utils.magic)
106
- !shouldRemove
107
- })
108
- ->keyValStringToAddress
109
- ->fromArray
110
- }
111
- }
112
-
113
- let addressCount = (mapping: mapping) => mapping.nameByAddress->Js.Dict.keys->Belt.Array.length
114
-
115
- let isEmpty = (mapping: mapping) => mapping->addressCount == 0