While on-boarding the user on the our platform, we are facing the below error intermittently for the some users and the error frequency rate is quite high, Could someone please help us for the same.
Let me know if any additional information is required:
- SDK Version:
“@tkey/common-types”: “^9.0.0”,
“@tkey/default”: “^9.0.1”,
“@tkey/security-questions”: “^9.0.0”,
“@tkey/service-provider-torus”: “^9.0.0”,
“@tkey/storage-layer-torus”: “^9.0.0”,
“@tkey/web-storage”: “^9.0.0”,
“@toruslabs/customauth”: “^13.0.0”,
“@web3auth/base”: “^6.1.1”,
“@web3auth/ethereum-provider”: “^6.1.5”, - Platform: Web browser/JS
- Browser Console Screenshots:
Different intermittent errors for some users:
'TypeError: Cannot convert undefined or null to object\n' +
' at Function.keys (<anonymous>)\n' +
' at V._refreshShares (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:11473)\n' +
' at V.generateNewShare (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:11023)\n' +
' at m.generateNewShareWithSecurityQuestions (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:9:37093)\n' +
' at r.Web3AuthProvider.generateNewShareWithSecurityPassphrase (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:171034)\n' +
' at async r.Web3AuthProvider.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:169455)\n' +
' at async f.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:181040)\n' +
' at async tY (https://wallet.zblocks.io/_next/static/chunks/pages/_app-3a54ad13a186fad3.js:86:546801)\n' +
' at async tG (https://wallet.zblocks.io/_next/static/chunks/pages/_app-3a54ad13a186fad3.js:86:548233)'
}
'WalletError: Failed to fetch the key provider.\n' +
' at r.Web3AuthProvider.getKeyProvider (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:167783)\n' +
' at async f.getKeyProvider (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:180415)\n' +
' at async f.getAddress (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:181223)\n'
stack: 'CoreError: setMetadata errored {"error":{"index":0,"timestamp":"Message has been signed more than 90s ago"},"success":false}\n' +
' at f.fromCode (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:2:165362)\n' +
' at f.metadataPostFailed (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:2:165982)\n' +
' at V.syncLocalMetadataTransitions (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:14838)\n' +
' at async V.addLocalMetadataTransitions (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:14337)\n' +
' at async V._initializeNewKey (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:13502)\n' +
' at async V.initialize (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:6200)\n' +
' at async r.Web3AuthProvider.initializeTkey (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:170199)\n' +
' at async r.Web3AuthProvider.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:169062)\n' +
' at async f.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:181040)\n' +
' at async tY (https://wallet.zblocks.io/_next/static/chunks/pages/_app-3a54ad13a186fad3.js:86:546801)'
CoreError: getMetadata errored Failed to fetch\n' +
' at Function.fromCode (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:2:165362)\n' +
' at Function.metadataGetFailed (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:2:165864)\n' +
' at V.getGenericMetadataWithTransitionStates (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:19157)\n' +
' at async V.initialize (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:4:5920)\n' +
' at async r.Web3AuthProvider.initializeTkey (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:170199)\n' +
' at async r.Web3AuthProvider.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:169062)\n' +
' at async f.connect (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:15:181040)\n'
Error: Please serve redirect.html present in serviceworker folder of this package on https://wallet.zblocks.io/serviceworker/redirect\n' +
' at HTMLLinkElement.n.relList.n.relList.supports.n.relList.supports.n.onerror (https://wallet.zblocks.io/_next/static/chunks/5dfdcea7.355dbec6430e121c.js:10:659)'
- If the issue is related to Custom Authentication, please include the following information (optional):
- Verifier Name: zbyte-aqua-prod
- JWKS Endpoint: https://dplat.zbyte.io/zbyte-sso/oidc/community/metadata/jwks.json
- Sample idToken (JWT):
Code Implementation using the tkey/SDK:
export class Web3AuthProvider implements IWalletProvider {
private tKey: ThresholdKey;
private modules: ModuleMap;
private keyDetails: KeyDetails | undefined;
private loginParams: Web3AuthLoginParams;
private loginResponse: TorusLoginResponse | undefined;
private provider: any;
private isActive: boolean;
private isPopUp: boolean;
constructor(config: Web3AuthConfig) {
this.keyDetails = undefined;
this.isActive = false;
this.isPopUp = false;
this.loginParams = {
accessToken: "",
typeOfToken: DEFAULT_TOKEN_TYPE,
tokenExpiry: DEFAULT_TOKEN_EXPIRY,
clientId: config.clientId ?? "",
domain: config.domain ?? "",
typeOfLogin: DEFAULT_LOGIN_TYPE,
verifier: config.verifierName ?? "",
};
this.modules = {
webStorage: new WebStorageModule(),
securityQuestions: new SecurityQuestionsModule(),
};
directParams.network = config.networkType;
directParams.enableLogging = config?.enableLogging;
directParams.web3AuthClientId = config.web3AuthClientId ?? directParams.web3AuthClientId;
const serviceProvider = new TorusServiceProvider({ customAuthArgs: directParams });
const storageLayer = new TorusStorageLayer({
hostUrl: TORUS_METADATA_URL,
enableLogging: config?.enableLogging,
});
this.tKey = new ThresholdKey({
serviceProvider: serviceProvider,
storageLayer: storageLayer,
modules: this.modules,
});
}
isConnected(): boolean {
return this.isActive;
}
get getKeyDetails(): KeyDetails | undefined {
return this.keyDetails;
}
injectLoginParams(loginParams: Web3AuthLoginInput, isPopUp: boolean) {
this.loginParams.accessToken = loginParams.accessToken;
this.loginParams.tokenExpiry = loginParams.tokenExpiry ?? this.loginParams.tokenExpiry;
this.loginParams.typeOfToken = loginParams.typeOfToken ?? this.loginParams.typeOfToken;
this.loginParams.typeOfLogin = loginParams.typeOfLogin ?? this.loginParams.typeOfLogin;
this.isPopUp = isPopUp;
}
async getKeyProvider(networkConfig: NetworkConfig): Promise<IKeyProvider> {
try {
console.log("using rpc-url:", networkConfig.networkRpcUrl);
const ethereumPrivateKeyProvider = new EthereumPrivateKeyProvider({
config: {
chainConfig: convertToCustomChainConfig(networkConfig),
},
});
const reconstructedKey = (await this.tKey.reconstructKey()).privKey;
let privKey = reconstructedKey.toString("hex");
if (reconstructedKey.byteLength() !== 32) {
console.error("Key size is not 32 bytes : ", privKey);
throw new WalletError(ErrorCode.INVALID_PRIVATE_KEY);
}
if (privKey.length < 64) {
privKey = privKey.padStart(64, "0");
}
await ethereumPrivateKeyProvider.setupProvider(privKey);
console.log("setup provider created");
return new Web3AuthKeyProvider(ethereumPrivateKeyProvider);
} catch (error) {
throw new WalletError(ErrorCode.GET_KEY_PROVIDER_FAILED, error as Error);
}
}
public async connect(): Promise<any> {
this.loginResponse = await this.login();
await this.initializeTkey();
try {
await this.getLocalShareFromWeb();
} catch (error) {
const response: RecoveryShareResponse = await fetchPassphrase(
this.loginResponse.publicAddress,
this.loginParams.accessToken
);
response.data.passphrase == ""
? await this.triggerSetPassphraseEvent()
: await this.recoverUsingPassphrase(response.data.passphrase);
this.resetLocalDeviceShare();
console.info("key: ", this.tKey.getMetadata().pubKey.x.toString("hex"));
}
await this.generateNewShareWithSecurityPassphrase();
this.isActive = true;
return this.loginResponse?.userInfo;
}
private createLoginParam() {
const params: SubVerifierDetails = {
clientId: this.loginParams.clientId,
verifier: this.loginParams.verifier,
typeOfLogin: this.loginParams.typeOfLogin ?? DEFAULT_LOGIN_TYPE,
jwtParams: {
domain: this.loginParams.domain,
verifierIdField: VERIFIER_ID_FIELD,
response_type: TOKEN,
scope: "",
},
hash: `access_token=${this.loginParams.accessToken}&token_type=${this.loginParams.typeOfToken}&expires_in=${this.loginParams.tokenExpiry}`,
queryParameters: {},
};
if (this.isPopUp) {
delete params["hash"];
delete params["queryParameters"];
}
return params;
}
async login(): Promise<TorusLoginResponse> {
const torusProvider = this.tKey.serviceProvider as TorusServiceProvider;
await torusProvider.init({});
const response = await torusProvider.triggerLogin(this.createLoginParam());
return response;
}
public async initializeTkey() {
this.keyDetails = await this.tKey.initialize();
}
public async getLocalShareFromWeb() {
try {
const webStorageModule = this.modules.webStorage as WebStorageModule;
await webStorageModule.inputShareFromWebStorage();
} catch (error) {
console.info(
"Seems like local share is missing in this browser, trying to use recovery share"
);
throw error;
}
}
private async recoverUsingPassphrase(passphrase: string) {
const SecurityModule = this.tKey.modules.securityQuestions as SecurityQuestionsModule;
await SecurityModule.inputShareFromSecurityQuestions(passphrase);
}
public async changeSecurityShareInfo(
answer: string,
question = SECURITY_QUESTION,
isStore = true
) {
const SecurityModule = this.tKey.modules.securityQuestions as SecurityQuestionsModule;
if (isStore) {
await this.updatePassphrase(answer, question);
} else {
await this.updatePassphrase("", "");
}
await SecurityModule.changeSecurityQuestionAndAnswer(answer, question);
}
public async generateNewShareWithSecurityPassphrase() {
try {
(this.tKey.modules.securityQuestions as SecurityQuestionsModule).getSecurityQuestions();
} catch (error) {
const reconstruct = this.tKey.reconstructKey();
const result = this.createPassphrase();
for (let retry = 0; retry < 4; retry++) {
try {
const SecurityModule = this.tKey.modules.securityQuestions as SecurityQuestionsModule;
await reconstruct;
await SecurityModule.generateNewShareWithSecurityQuestions(
(
await result
).data.passphrase,
SECURITY_QUESTION
);
break;
} catch (error) {
console.error(error);
if (retry < 3) {
// Added exponential delay
// 0.5, 1, 1.5 secs.
sleep((retry + 1) * 500);
continue;
} else {
throw error;
}
}
}
}
}
public setModules(modules: ModuleMap) {
this.modules = modules;
this.tKey.modules = this.modules;
}
}