Socket
Socket
Sign inDemoInstall

abitype

Package Overview
Dependencies
Maintainers
2
Versions
180
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

abitype - npm Package Compare versions

Comparing version 0.10.3 to 1.0.0

2

dist/cjs/human-readable/errors/abiItem.js

@@ -9,3 +9,3 @@ "use strict";

details: `parseAbiItem(${JSON.stringify(signature, null, 2)})`,
docsPath: '/api/human.html#parseabiitem-1',
docsPath: '/api/human#parseabiitem-1',
});

@@ -12,0 +12,0 @@ Object.defineProperty(this, "name", {

@@ -9,3 +9,3 @@ "use strict";

details: `parseAbiParameter(${JSON.stringify(param, null, 2)})`,
docsPath: '/api/human.html#parseabiparameter-1',
docsPath: '/api/human#parseabiparameter-1',
});

@@ -25,3 +25,3 @@ Object.defineProperty(this, "name", {

details: `parseAbiParameters(${JSON.stringify(params, null, 2)})`,
docsPath: '/api/human.html#parseabiparameters-1',
docsPath: '/api/human#parseabiparameters-1',
});

@@ -28,0 +28,0 @@ Object.defineProperty(this, "name", {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '0.10.3';
exports.version = '1.0.0';
//# sourceMappingURL=version.js.map

@@ -6,3 +6,3 @@ import { BaseError } from '../../errors.js';

details: `parseAbiItem(${JSON.stringify(signature, null, 2)})`,
docsPath: '/api/human.html#parseabiitem-1',
docsPath: '/api/human#parseabiitem-1',
});

@@ -9,0 +9,0 @@ Object.defineProperty(this, "name", {

@@ -6,3 +6,3 @@ import { BaseError } from '../../errors.js';

details: `parseAbiParameter(${JSON.stringify(param, null, 2)})`,
docsPath: '/api/human.html#parseabiparameter-1',
docsPath: '/api/human#parseabiparameter-1',
});

@@ -21,3 +21,3 @@ Object.defineProperty(this, "name", {

details: `parseAbiParameters(${JSON.stringify(params, null, 2)})`,
docsPath: '/api/human.html#parseabiparameters-1',
docsPath: '/api/human#parseabiparameters-1',
});

@@ -24,0 +24,0 @@ Object.defineProperty(this, "name", {

@@ -1,2 +0,2 @@

export const version = '0.10.3';
export const version = '1.0.0';
//# sourceMappingURL=version.js.map

@@ -1,2 +0,2 @@

import type { Abi, AbiParameter, AbiParameterKind, AbiStateMutability, AbiType, MBits, SolidityAddress, SolidityArray, SolidityBool, SolidityBytes, SolidityFixedArrayRange, SolidityFixedArraySizeLookup, SolidityFunction, SolidityInt, SolidityString, SolidityTuple, TypedData, TypedDataParameter, TypedDataType } from './abi.js';
import type { Abi, AbiParameter, AbiParameterKind, AbiStateMutability, AbiType, MBits, SolidityArray, SolidityBytes, SolidityFixedArrayRange, SolidityFixedArraySizeLookup, SolidityInt, SolidityTuple, TypedData, TypedDataParameter, TypedDataType } from './abi.js';
import type { ResolvedRegister } from './register.js';

@@ -13,29 +13,24 @@ import type { Error, Merge, Pretty, Tuple } from './types.js';

*/
export type AbiTypeToPrimitiveType<TAbiType extends AbiType, TAbiParameterKind extends AbiParameterKind = AbiParameterKind> = PrimitiveTypeLookup<TAbiType, TAbiParameterKind>[TAbiType];
type PrimitiveTypeLookup<TAbiType extends AbiType, TAbiParameterKind extends AbiParameterKind = AbiParameterKind> = {
[_ in SolidityAddress]: ResolvedRegister['AddressType'];
} & {
[_ in SolidityBool]: boolean;
} & {
[_ in SolidityBytes]: ResolvedRegister['BytesType'][TAbiParameterKind];
} & {
[_ in SolidityFunction]: `${ResolvedRegister['AddressType']}${string}`;
} & {
[_ in SolidityInt]: TAbiType extends `${'u' | ''}int${infer TBits}` ? TBits extends keyof BitsTypeLookup ? BitsTypeLookup[TBits] : Error<'Unknown bits value.'> : Error<`Unknown 'SolidityInt' format.`>;
} & {
[_ in SolidityString]: string;
} & {
[_ in SolidityTuple]: Record<string, unknown>;
} & {
export type AbiTypeToPrimitiveType<TAbiType extends AbiType, TAbiParameterKind extends AbiParameterKind = AbiParameterKind> = TAbiType extends SolidityBytes ? PrimitiveTypeLookup[TAbiType][TAbiParameterKind] : PrimitiveTypeLookup[TAbiType];
interface PrimitiveTypeLookup extends SolidityIntMap, SolidityByteMap, SolidityArrayMap {
address: ResolvedRegister['AddressType'];
bool: boolean;
function: `${ResolvedRegister['AddressType']}${string}`;
string: string;
tuple: Record<string, unknown>;
}
type SolidityIntMap = {
[_ in SolidityInt]: _ extends `${'u' | ''}int${infer TBits extends keyof BitsTypeLookup}` ? BitsTypeLookup[TBits] : never;
};
type SolidityByteMap = {
[_ in SolidityBytes]: ResolvedRegister['BytesType'];
};
type SolidityArrayMap = {
[_ in SolidityArray]: readonly unknown[];
};
type GreaterThan48Bits = Exclude<MBits, 8 | 16 | 24 | 32 | 40 | 48 | ''>;
type LessThanOrEqualTo48Bits = Exclude<MBits, GreaterThan48Bits | ''>;
type NoBits = Exclude<MBits, GreaterThan48Bits | LessThanOrEqualTo48Bits>;
type GreaterThan48Bits = Exclude<MBits, 8 | 16 | 24 | 32 | 40 | 48 | NoBits>;
type LessThanOrEqualTo48Bits = Exclude<MBits, GreaterThan48Bits | NoBits>;
type NoBits = '';
type BitsTypeLookup = {
[_ in `${LessThanOrEqualTo48Bits}`]: ResolvedRegister['IntType'];
} & {
[_ in `${GreaterThan48Bits}`]: ResolvedRegister['BigIntType'];
} & {
[_ in NoBits]: ResolvedRegister['BigIntType'];
[K in MBits]: ResolvedRegister[K extends LessThanOrEqualTo48Bits ? 'IntType' : 'BigIntType'];
};

@@ -52,14 +47,18 @@ /**

type: unknown;
}, TAbiParameterKind extends AbiParameterKind = AbiParameterKind> = TAbiParameter['type'] extends Exclude<AbiType, SolidityTuple | SolidityArray> ? AbiTypeToPrimitiveType<TAbiParameter['type'], TAbiParameterKind> : TAbiParameter extends {
}, TAbiParameterKind extends AbiParameterKind = AbiParameterKind> = TAbiParameter['type'] extends AbiBasicType ? AbiTypeToPrimitiveType<TAbiParameter['type'], TAbiParameterKind> : TAbiParameter extends {
type: SolidityTuple;
components: infer TComponents extends readonly AbiParameter[];
} ? TComponents extends readonly [] ? [] : _HasUnnamedAbiParameter<TComponents> extends true ? readonly [
...{
[K in keyof TComponents]: AbiParameterToPrimitiveType<TComponents[K], TAbiParameterKind>;
}
] : {
[Component in TComponents[number] as Component extends {
name: string;
} ? Component['name'] : never]: AbiParameterToPrimitiveType<Component, TAbiParameterKind>;
} :
} ? AbiComponentsToPrimitiveType<TComponents, TAbiParameterKind> : MaybeExtractArrayParameterType<TAbiParameter['type']> extends [
infer Head extends string,
infer Size
] ? AbiArrayToPrimitiveType<TAbiParameter, TAbiParameterKind, Head, Size> : ResolvedRegister['StrictAbiType'] extends true ? Error<`Unknown type '${TAbiParameter['type'] & string}'.`> : TAbiParameter extends {
components: Error<string>;
} ? TAbiParameter['components'] : unknown;
type AbiBasicType = Exclude<AbiType, SolidityTuple | SolidityArray>;
type AbiComponentsToPrimitiveType<Components extends readonly AbiParameter[], TAbiParameterKind extends AbiParameterKind> = Components extends readonly [] ? [] : Components[number]['name'] extends Exclude<Components[number]['name'] & string, undefined | ''> ? {
[Component in Components[number] as Component['name'] & {}]: AbiParameterToPrimitiveType<Component, TAbiParameterKind>;
} : {
[I in keyof Components]: AbiParameterToPrimitiveType<Components[I], TAbiParameterKind>;
};
type MaybeExtractArrayParameterType<T> =
/**

@@ -73,15 +72,11 @@ * First, infer `Head` against a known size type (either fixed-length array value or `""`).

*/
TAbiParameter['type'] extends `${infer Head}[${'' | `${SolidityFixedArrayRange}`}]` ? TAbiParameter['type'] extends `${Head}[${infer Size}]` ? Size extends keyof SolidityFixedArraySizeLookup ? Tuple<AbiParameterToPrimitiveType<Merge<TAbiParameter, {
T extends `${infer Head}[${'' | `${SolidityFixedArrayRange}`}]` ? T extends `${Head}[${infer Size}]` ? [Head, Size] : undefined : undefined;
type AbiArrayToPrimitiveType<TAbiParameter extends AbiParameter | {
name: string;
type: unknown;
}, TAbiParameterKind extends AbiParameterKind, Head extends string, Size> = Size extends keyof SolidityFixedArraySizeLookup ? Tuple<AbiParameterToPrimitiveType<Merge<TAbiParameter, {
type: Head;
}>, TAbiParameterKind>, SolidityFixedArraySizeLookup[Size]> : readonly AbiParameterToPrimitiveType<Merge<TAbiParameter, {
type: Head;
}>, TAbiParameterKind>[] : never : ResolvedRegister['StrictAbiType'] extends true ? TAbiParameter['type'] extends infer TAbiType extends string ? Error<`Unknown type '${TAbiType}'.`> : never : TAbiParameter extends {
components: Error<string>;
} ? TAbiParameter['components'] : unknown;
type _HasUnnamedAbiParameter<TAbiParameters extends readonly AbiParameter[]> = TAbiParameters extends readonly [
infer Head extends AbiParameter,
...infer Tail extends readonly AbiParameter[]
] ? Head extends {
name: string;
} ? Head['name'] extends '' ? true : _HasUnnamedAbiParameter<Tail> : true : false;
}>, TAbiParameterKind>[];
/**

@@ -220,3 +215,3 @@ * Converts array of {@link AbiParameter} to corresponding TypeScript primitive types.

};
};
} & unknown;
type _TypedDataParametersToAbiParameters<TTypedDataParameters extends readonly TypedDataParameter[], TTypedData extends TypedData, TKeyReferences extends {

@@ -223,0 +218,0 @@ [_: string]: unknown;

@@ -1,2 +0,2 @@

export declare const version = "0.10.3";
export declare const version = "1.0.0";
//# sourceMappingURL=version.d.ts.map
{
"name": "abitype",
"description": "Strict TypeScript types for Ethereum ABIs",
"version": "0.10.3",
"version": "1.0.0",
"license": "MIT",

@@ -14,2 +14,3 @@ "repository": "wevm/abitype",

"!src/**/*.bench.ts",
"!src/**/*.bench-d.ts",
"/abis",

@@ -70,4 +71,4 @@ "/zod"

"contributors": [
"awkweb.eth <t@wagmi.sh>",
"jxom.eth <j@wagmi.sh>"
"awkweb.eth <t@wevm.dev>",
"jxom.eth <j@wevm.dev>"
],

@@ -79,7 +80,7 @@ "funding": "https://github.com/sponsors/wevm",

"ethereum",
"types",
"typescript",
"types",
"web3",
"viem",
"wagmi",
"web3",
"wevm"

@@ -93,4 +94,6 @@ ],

"test:build": "publint --strict",
"typecheck": "tsc --noEmit"
"typebench": "tsx src/**.bench-d.ts --benchPercentThreshold 20 --benchErrorOnThresholdExceeded",
"typecheck": "tsc --noEmit",
"typeperf": "tsc --noEmit --extendedDiagnostics --composite false --incremental false"
}
}

@@ -72,6 +72,6 @@ <br/>

- You want to [typecheck](https://abitype.dev/api/types.html) your ABIs or EIP-712 Typed Data.
- You want to [typecheck](https://abitype.dev/api/types) your ABIs or EIP-712 Typed Data.
- You want to add type inference and autocomplete to your library based on user-provided ABIs or EIP-712 Typed Data, like [wagmi](https://wagmi.sh) and [viem](https://viem.sh).
- You need to [convert ABI types](https://abitype.dev/api/utilities.html#abiparameterstoprimitivetypes) (e.g. `'string'`) to TypeScript types (e.g. `string`) or other type transformations.
- You need to validate ABIs at [runtime](https://abitype.dev/api/zod.html) (e.g. after fetching from external resource).
- You need to [convert ABI types](https://abitype.dev/api/utilities#abiparameterstoprimitivetypes) (e.g. `'string'`) to TypeScript types (e.g. `string`) or other type transformations.
- You need to validate ABIs at [runtime](https://abitype.dev/api/zod) (e.g. after fetching from external resource).
- You don’t want to set up a build process to generate types (e.g. TypeChain).

@@ -78,0 +78,0 @@

@@ -9,3 +9,3 @@ import { BaseError } from '../../errors.js'

details: `parseAbiItem(${JSON.stringify(signature, null, 2)})`,
docsPath: '/api/human.html#parseabiitem-1',
docsPath: '/api/human#parseabiitem-1',
})

@@ -12,0 +12,0 @@ }

@@ -11,3 +11,3 @@ import type { AbiItemType, AbiParameter } from '../../abi.js'

details: `parseAbiParameter(${JSON.stringify(param, null, 2)})`,
docsPath: '/api/human.html#parseabiparameter-1',
docsPath: '/api/human#parseabiparameter-1',
})

@@ -23,3 +23,3 @@ }

details: `parseAbiParameters(${JSON.stringify(params, null, 2)})`,
docsPath: '/api/human.html#parseabiparameters-1',
docsPath: '/api/human#parseabiparameters-1',
})

@@ -26,0 +26,0 @@ }

@@ -8,11 +8,7 @@ import type {

MBits,
SolidityAddress,
SolidityArray,
SolidityBool,
SolidityBytes,
SolidityFixedArrayRange,
SolidityFixedArraySizeLookup,
SolidityFunction,
SolidityInt,
SolidityString,
SolidityTuple,

@@ -38,40 +34,41 @@ TypedData,

TAbiParameterKind extends AbiParameterKind = AbiParameterKind,
> = PrimitiveTypeLookup<TAbiType, TAbiParameterKind>[TAbiType]
> = TAbiType extends SolidityBytes
? // If PrimitiveTypeLookup is missing key values from AbiType,
// there will be an error on this property access
PrimitiveTypeLookup[TAbiType][TAbiParameterKind]
: PrimitiveTypeLookup[TAbiType]
// Using a map to look up types is faster, than nested conditional types
// s/o https://twitter.com/SeaRyanC/status/1538971176357113858
type PrimitiveTypeLookup<
TAbiType extends AbiType,
TAbiParameterKind extends AbiParameterKind = AbiParameterKind,
> = {
[_ in SolidityAddress]: ResolvedRegister['AddressType']
} & {
[_ in SolidityBool]: boolean
} & {
[_ in SolidityBytes]: ResolvedRegister['BytesType'][TAbiParameterKind]
} & {
[_ in SolidityFunction]: `${ResolvedRegister['AddressType']}${string}`
} & {
[_ in SolidityInt]: TAbiType extends `${'u' | ''}int${infer TBits}`
? TBits extends keyof BitsTypeLookup
? BitsTypeLookup[TBits]
: Error<'Unknown bits value.'>
: Error<`Unknown 'SolidityInt' format.`>
} & {
[_ in SolidityString]: string
} & {
[_ in SolidityTuple]: Record<string, unknown>
} & {
[_ in SolidityArray]: readonly unknown[]
interface PrimitiveTypeLookup
extends SolidityIntMap,
SolidityByteMap,
SolidityArrayMap {
address: ResolvedRegister['AddressType']
bool: boolean
function: `${ResolvedRegister['AddressType']}${string}`
string: string
tuple: Record<string, unknown>
}
type GreaterThan48Bits = Exclude<MBits, 8 | 16 | 24 | 32 | 40 | 48 | ''>
type LessThanOrEqualTo48Bits = Exclude<MBits, GreaterThan48Bits | ''>
type NoBits = Exclude<MBits, GreaterThan48Bits | LessThanOrEqualTo48Bits>
type SolidityIntMap = {
[_ in SolidityInt]: _ extends `${
| 'u'
| ''}int${infer TBits extends keyof BitsTypeLookup}`
? BitsTypeLookup[TBits]
: never
}
type SolidityByteMap = {
[_ in SolidityBytes]: ResolvedRegister['BytesType']
}
type SolidityArrayMap = { [_ in SolidityArray]: readonly unknown[] }
type GreaterThan48Bits = Exclude<MBits, 8 | 16 | 24 | 32 | 40 | 48 | NoBits>
type LessThanOrEqualTo48Bits = Exclude<MBits, GreaterThan48Bits | NoBits>
type NoBits = ''
type BitsTypeLookup = {
[_ in `${LessThanOrEqualTo48Bits}`]: ResolvedRegister['IntType']
} & {
[_ in `${GreaterThan48Bits}`]: ResolvedRegister['BigIntType']
} & {
[_ in NoBits]: ResolvedRegister['BigIntType']
[K in MBits]: ResolvedRegister[K extends LessThanOrEqualTo48Bits
? 'IntType'
: 'BigIntType']
}

@@ -89,7 +86,4 @@

TAbiParameterKind extends AbiParameterKind = AbiParameterKind,
> = TAbiParameter['type'] extends Exclude<
// 1. Check to see if type is basic (not tuple or array) and can be looked up immediately.
AbiType,
SolidityTuple | SolidityArray
>
> = TAbiParameter['type'] extends AbiBasicType
? AbiTypeToPrimitiveType<TAbiParameter['type'], TAbiParameterKind>

@@ -101,60 +95,9 @@ : // 2. Check if type is tuple and covert each component

}
? TComponents extends readonly []
? []
: _HasUnnamedAbiParameter<TComponents> extends true
? // Has unnamed tuple parameters so return as array
readonly [
...{
[K in keyof TComponents]: AbiParameterToPrimitiveType<
TComponents[K],
TAbiParameterKind
>
},
]
: // All tuple parameters are named so return as object
{
[Component in
TComponents[number] as Component extends {
name: string
}
? Component['name']
: never]: AbiParameterToPrimitiveType<Component, TAbiParameterKind>
}
? AbiComponentsToPrimitiveType<TComponents, TAbiParameterKind>
: // 3. Check if type is array.
/**
* First, infer `Head` against a known size type (either fixed-length array value or `""`).
*
* | Input | Head |
* | --------------- | ------------ |
* | `string[]` | `string` |
* | `string[][][3]` | `string[][]` |
*/
TAbiParameter['type'] extends `${infer Head}[${
| ''
| `${SolidityFixedArrayRange}`}]`
? /**
* Then, infer in the opposite direction, using the known `Head` to infer the exact `Size` value.
*
* | Input | Size |
* | ------------ | ---- |
* | `${Head}[]` | `""` |
* | `${Head}[3]` | `3` |
*/
TAbiParameter['type'] extends `${Head}[${infer Size}]`
? // Check if size is within range for fixed-length arrays, if so create a tuple.
// Otherwise, create an array. Tuples and arrays are created with `[${Size}]` popped off the end
// and passed back into the function to continue reduing down to the basic types found in Step 1.
Size extends keyof SolidityFixedArraySizeLookup
? Tuple<
AbiParameterToPrimitiveType<
Merge<TAbiParameter, { type: Head }>,
TAbiParameterKind
>,
SolidityFixedArraySizeLookup[Size]
>
: readonly AbiParameterToPrimitiveType<
Merge<TAbiParameter, { type: Head }>,
TAbiParameterKind
>[]
: never
MaybeExtractArrayParameterType<TAbiParameter['type']> extends [
infer Head extends string,
infer Size,
]
? AbiArrayToPrimitiveType<TAbiParameter, TAbiParameterKind, Head, Size>
: // 4. If type is not basic, tuple, or array, we don't know what the type is.

@@ -164,5 +107,3 @@ // This can happen when a fixed-length array is out of range (`Size` doesn't exist in `SolidityFixedArraySizeLookup`),

ResolvedRegister['StrictAbiType'] extends true
? TAbiParameter['type'] extends infer TAbiType extends string
? Error<`Unknown type '${TAbiType}'.`>
: never
? Error<`Unknown type '${TAbiParameter['type'] & string}'.`>
: // 5. If we've gotten this far, let's check for errors in tuple components.

@@ -174,15 +115,74 @@ // (Happens for recursive tuple typed data types.)

// TODO: Speed up by returning immediately as soon as named parameter is found.
type _HasUnnamedAbiParameter<TAbiParameters extends readonly AbiParameter[]> =
TAbiParameters extends readonly [
infer Head extends AbiParameter,
...infer Tail extends readonly AbiParameter[],
]
? Head extends { name: string }
? Head['name'] extends ''
? true
: _HasUnnamedAbiParameter<Tail>
: true
: false
type AbiBasicType = Exclude<AbiType, SolidityTuple | SolidityArray>
type AbiComponentsToPrimitiveType<
Components extends readonly AbiParameter[],
TAbiParameterKind extends AbiParameterKind,
> = Components extends readonly []
? []
: // Compare the original set of names to a "validated"
// set where each name is coerced to a string and undefined|"" are excluded
Components[number]['name'] extends Exclude<
Components[number]['name'] & string,
undefined | ''
>
? // If all the original names are present, all tuple parameters are named so return as object
{
[Component in
Components[number] as Component['name'] & {}]: AbiParameterToPrimitiveType<
Component,
TAbiParameterKind
>
}
: // Otherwise, has unnamed tuple parameters so return as array
{
[I in keyof Components]: AbiParameterToPrimitiveType<
Components[I],
TAbiParameterKind
>
}
type MaybeExtractArrayParameterType<T> =
/**
* First, infer `Head` against a known size type (either fixed-length array value or `""`).
*
* | Input | Head |
* | --------------- | ------------ |
* | `string[]` | `string` |
* | `string[][][3]` | `string[][]` |
*/
T extends `${infer Head}[${'' | `${SolidityFixedArrayRange}`}]`
? // * Then, infer in the opposite direction, using the known `Head` to infer the exact `Size` value.
// *
// * | Input | Size |
// * | ------------ | ---- |
// * | `${Head}[]` | `""` |
// * | `${Head}[3]` | `3` |
// */
T extends `${Head}[${infer Size}]`
? [Head, Size]
: undefined
: undefined
type AbiArrayToPrimitiveType<
TAbiParameter extends AbiParameter | { name: string; type: unknown },
TAbiParameterKind extends AbiParameterKind,
Head extends string,
Size,
> = Size extends keyof SolidityFixedArraySizeLookup
? // Check if size is within range for fixed-length arrays, if so create a tuple.
Tuple<
AbiParameterToPrimitiveType<
Merge<TAbiParameter, { type: Head }>,
TAbiParameterKind
>,
SolidityFixedArraySizeLookup[Size]
>
: // Otherwise, create an array. Tuples and arrays are created with `[${Size}]` popped off the end
// and passed back into the function to continue reducing down to the basic types found in Step 1.
readonly AbiParameterToPrimitiveType<
Merge<TAbiParameter, { type: Head }>,
TAbiParameterKind
>[]
/**

@@ -406,3 +406,4 @@ * Converts array of {@link AbiParameter} to corresponding TypeScript primitive types.

}
}
// Ensure the result is "Prettied"
} & unknown

@@ -409,0 +410,0 @@ type _TypedDataParametersToAbiParameters<

@@ -1,1 +0,1 @@

export const version = '0.10.3'
export const version = '1.0.0'

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc